본문 바로가기
코딩 테스트 연습/백준 bronze

[백준] B2. 피보나치 수 5 (Python)

by 카누가 좋아요 2023. 6. 30.

❓ 문제

10870번: 피보나치 수 5 (acmicpc.net)

 

10870번: 피보나치 수 5

피보나치 수는 0과 1로 시작한다. 0번째 피보나치 수는 0이고, 1번째 피보나치 수는 1이다. 그 다음 2번째 부터는 바로 앞 두 피보나치 수의 합이 된다. 이를 식으로 써보면 Fn = Fn-1 + Fn-2 (n ≥ 2)가

www.acmicpc.net

 

 

 

💡 해결하기

피보나치 수는 다음과 같은 시퀀스가 성립한다.

 

 

➡️ 0번째 피보나치 수는 0, 1번째 피보나치 수는 1로 정의한다.

➡️ n번째 피보나치 수는(n >= 2) n - 1 번째의 피보나치 수와 n - 2번째의 피보나치 수의 합이 된다.

 

예를 들어, 3번째 피보나치 수를 구한다고 하면 다음과 같은 과정을 통해 구해야 한다.

F3 = F2 + F1 = (F1 + F0) + 1 = (1 + 0) + 1 = 2

즉, n번째 피보나치 수를 구하는 과정에는 n - 1, n - 2, ... , 0번째 피보나치 수를 구하는 과정이 포함되어 있는 것이다.

따라서 피보나치 수를 구하는 과정은 n을 1씩 줄여가며 재귀적으로 구현할 수 있고, 종료 조건n이 1이나 0이 되었을 때가 된다.

 

 

 

💻 Python으로 코드 작성하기

 

# 정수 입력받기
n = int(input())

# 피보나치 수 구하는 과정 구현
def fibonacci(n):
    if n == 0:     # n이 0일 경우
        return 0     # 정의에 따라 0 반환
    elif n == 1:     # n이 1일 경우
    	return 1     # 정의에 따라 1 반환
    else:     # n이 2 이상일 경우
    	return fibonacci(n - 1) + fibonacci(n - 2)     # fibonacci 함수에 n-1과 n-2의 값을 전달하며 재귀 호출
        
print(fibonacci(n))

 

위의 경우에는 fibonacci 함수가 2번씩 재귀 호출되므로 fibonacci(n-1)이 먼저 실행된 다음에 fibonacci(n)이 그 다음으로 실행된다.

n으로 5를 입력받았을 때를 살펴보면 다음과 같은 순서로 fibonacci 함수 호출이 된다.

 

위 코드가 잘 실행되기는 하지만 효율성이 떨어지는 면이 있다.

위 실행 과정을 보면 7번 과정을 통해 f(3)에서 사용될 f(2)(n - 1)를 이미 구해놓았는데 13번 과정에서 f(4)에 사용될 f(2)(n - 2)를 또 구하고 있다. 두 경우에 사용될 f(2)의 값은 동일한데 말이다.

입력 숫자의 크기가 커질수록 위와 같이 이미 구한 적이 있는 값을 또 구하는 과정이 더 많이 반복될 것이고 이는 곧 시간 초과로 이어질 수 있다.

 

따라서 이미 구해놓은 값은 기록하는 방식을 사용하여 또 구하지 않게 하는 코드로 개선할 필요가 있다.

그려려면 다음과 같이 딕셔너리를 이용해 구한 값을 기록하여 현재 n값이 딕셔너리의 key로 존재하는지 매번 확인하는 코드를 작성하면 된다.

 

👩‍🔧 코드 개선하기

 

n = int(input())

record = {0: 0, 1: 1}     # 이미 정의되어 있는 0번째, 1번째 피보나치 수는 미리 기록해 놓기

def fibonacci(n):
	if n in record:     # 현재 n이 record에 key로 존재하면
        return record[n]     # 그 value를 반환
    else:     # 현재 n이 record에 key로 존재하지 않는다면
    	record[n] = fibonacci(n - 1) + fibonacci(n - 2)     # n번째 피보나치 수에 대한 정보를 record 딕셔너리에 기록
     	return record[n]     # record[n]의 값이 곧 fibonacci(n - 1) + fibonacci(n - 2)의 값이므로 결국 위의 코드와 동일

print(fibonacci(n))

 

위와 같이 작성하면 시간이 많이 줄긴 하지만 큰 숫자를 입력하였을 때 recursion 횟수를 초과했다는 RecursionError를 만나게 될 수 있다.

 

따라서 완전히 오류 없이 풀어내기 위해서는 재귀가 아닌 반복문을 이용하여 코드를 작성해야 한다.

바로 위의 코드에서 딕셔너리를 리스트로, 재귀 함수를 반복문으로 바꾸어 작성하기만 하면 된다.

 

👩‍🔧 코드 개선하기

 

n = int(input())     

record = [0, 1]     # 0번째, 1번째 피보나치 수는 정의대로 먼저 기록, 후의 피보나치 수들을 계속 누적할 리스트

if n == 0 or n == 1:     # 입력된 숫자가 0 또는 1이면
    print(record[n])     # 바로 record에서 찾아 반환
else:     # 입력된 숫자가 2 이상이면
    for i in range(2, n + 1):     # 2부터 n까지 단계를 거치면서 n번째 피보나치 수 찾기
        record.append(record[-1] + record[-2])     # i번째 피보나치 수는 i-1번째(record[-1])와 i-2(record[-2])번째 피보나치 수의 합, 그것을 record의 마지막 요소로 기록
    print(record[-1])     # 기록이 모두 끝난 후 record의 제일 마지막 요소가 n번째 피보나치 수

 

 

 

📌 참고한 영상

(32) 코딩테스트 출제자가 파놓은 함정: 재귀함수 - YouTube

댓글