Algorithm/백준

[백준] 28702 - FizzBuzz

비번변경 2024. 7. 1. 18:59

문제

문제 : 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