문제
문제 : https://www.acmicpc.net/problem/28702
FizzBuzz 문제는 i = 1, 2, 3,... 에 대해 다음 규칙에 따라 문자열을 한 줄에 하나씩 출력하는 문제이다.
- i가 3의 배수이면서 5의 배수이면 FizzBuzz를 출력한다.
- i가 3의 배수이면서 5의 배수가 아니면 Fizz를 출력한다.
- i가 3의 배수가 아니면서 5의 배수이면 Buzz를 출력한다.
- i가 3의 배수가 아니면서 5의 배수도 아니면 i 값을 출력한다.
연속으로 출력된 세 개의 문자열이 주어질 때 이 세 문자열 다음에 올 문자열은 무엇인가?
풀이
값이 출력되는 규칙을 확인해보면 3과 5의 최소공배수인 15를 주기로 출력 패턴이 반복되는 것을 확인할 수 있다. 따라서 출력 규칙을 만들고,
1. 출력 규칙 생성
rules = []
size = 15
for i in range(1, size + 1):
rule = ''
if i % 3 == 0:
rule += 'Fizz'
if i % 5 == 0:
rule += 'Buzz'
rules.append(rule if rule != '' else i)
# 인덱스가 14 - 16 인 경우를 처리하기 위한 반복
rules *= 2
2. 입력값 초기화
list_input = [sys.stdin.readline().strip() for _ in range(3)]
3. 출력 규칙과 비교하기 위한 입력값 처리
입력값을 출력 규칙과 비교하기 위해 숫자를 15로 나눈다.
list_cast = [int(i) % size if i.isnumeric() else i for i in list_input]
3. 출력할 값이 숫자인 경우, 기존 입력값 크기로 원복 하기 위한 몫을 구한다.
mul = [int(i) // size for i in list_input if i.isnumeric()][0]
4. 전처리한 입력값과 출력 규칙이 일치하는 인덱스를 찾는다.
만약 인덱스가 15를 넘어가면 15로 나눈 나머지를 인덱스로 한다.
idx = [i for i in range(len(rules)) if list_cast == rules[i:i + 3]][0]
idx_rolling = (idx + 3) % size
5. 결과 출력
만약 출력 규칙 내 값이 숫자이면 3번에서 구한 몫을 사용하여 출력할 숫자값을 계산한다. 그렇지 않으면 출력 규칙 내 값을 그대로 출력한다.
answer = mul * size + idx + 4 if isinstance(rules[idx_rolling], int) else rules[idx_rolling]
print(answer)
전체 코드는 접은 글로 적어둔다.
import sys
rules = []
size = 15
for i in range(1, size + 1):
rule = ''
if i % 3 == 0:
rule += 'Fizz'
if i % 5 == 0:
rule += 'Buzz'
rules.append(rule if rule != '' else i)
rules *= 2
list_input = [sys.stdin.readline().strip() for _ in range(3)]
list_cast = [int(i) % size if i.isnumeric() else i for i in list_input]
mul = [int(i) // size for i in list_input if i.isnumeric()][0]
idx = [i for i in range(len(rules)) if list_cast == rules[i:i + 3]][0]
idx_rolling = (idx + 3) % size
answer = mul * size + idx + 4 if isinstance(rules[idx_rolling], int) else rules[idx_rolling]
print(answer)
다른 풀이
혹시 더 좋은 풀이가 없을까 찾다가 입력의 중에 포함되는 숫자값을 사용하여 출력해야 할 i 값을 계산하는 방식을 찾았다. 수정하니 코드가 훨씬 간결해져서 적어둔다.
1. 입력값 초기화
import sys
list_input = [sys.stdin.readline().strip() for _ in range(3)]
2. 출력할 i 계산
입력값에는 반드시 숫자값이 포함되어 있고, 이는 둘 이상일 수도 있다. 첫 번째 값만 가져오면 된다.
val = [int(v) + (3 - i) for i, v in enumerate(list_input) if v.isnumeric()][0]
3. 조건 별 출력값 초기화
i가 3의 배수인지, 5의 배수인지에 따라 출력할 문자열을 결정한다.
answer = ""
if val % 3 == 0:
answer += 'Fizz'
if val % 5 == 0:
answer += 'Buzz'
4. 값 출력
문자열이 비어있으면 숫자 i를 그대로 출력하고 그렇지 않으면 3번에서 초기화한 문자열을 출력한다.
print(answer if answer != '' else val)
마찬가지로 전체 코드는 접은글로 적어둔다.
import sys
# 입력값 초기화
list_input = [sys.stdin.readline().strip() for _ in range(3)]
# 출력할 i 계산
val = [int(v) + (3 - i) for i, v in enumerate(list_input) if v.isnumeric()][0]
# 조건 별 출력값 초기화
answer = ""
if val % 3 == 0:
answer += 'Fizz'
if val % 5 == 0:
answer += 'Buzz'
# 출력
print(answer if answer != '' else val)
참고 문서
https://www.acmicpc.net/problem/28702