[파이썬][백준 1003번] 피보나치 함수
1. 문제
[Silver III] 피보나치 함수 - 1003
성능 요약
메모리: 30840 KB, 시간: 80 ms
분류
다이나믹 프로그래밍(dp)
문제 설명
다음 소스는 N번째 피보나치 수를 구하는 C++ 함수이다.
int fibonacci(int n) { if (n == 0) { printf("0"); return 0; } else if (n == 1) { printf("1"); return 1; } else { return fibonacci(n‐1) + fibonacci(n‐2); } }
fibonacci(3)
을 호출하면 다음과 같은 일이 일어난다.
fibonacci(3)
은fibonacci(2)
와fibonacci(1)
(첫 번째 호출)을 호출한다.fibonacci(2)
는fibonacci(1)
(두 번째 호출)과fibonacci(0)
을 호출한다.- 두 번째 호출한
fibonacci(1)
은 1을 출력하고 1을 리턴한다. fibonacci(0)
은 0을 출력하고, 0을 리턴한다.fibonacci(2)
는fibonacci(1)
과fibonacci(0)
의 결과를 얻고, 1을 리턴한다.- 첫 번째 호출한
fibonacci(1)
은 1을 출력하고, 1을 리턴한다. fibonacci(3)
은fibonacci(2)
와fibonacci(1)
의 결과를 얻고, 2를 리턴한다.
1은 2번 출력되고, 0은 1번 출력된다. N이 주어졌을 때, fibonacci(N)
을 호출했을 때, 0과 1이 각각 몇 번 출력되는지 구하는 프로그램을 작성하시오.
입력
첫째 줄에 테스트 케이스의 개수 T가 주어진다.
각 테스트 케이스는 한 줄로 이루어져 있고, N이 주어진다. N은 40보다 작거나 같은 자연수 또는 0이다.
출력
각 테스트 케이스마다 0이 출력되는 횟수와 1이 출력되는 횟수를 공백으로 구분해서 출력한다.
출처: 백준, https://https://www.acmicpc.net/
2. 해결방법 시간복잡도
- DP 탑다운 O(N^2)
3. 문제 해결 및 코드
-
주석을 참고하면서 이해를 돕습니다.
4. 알고리즘 및 해설
- 해당 문제에 사용된 피보나치 수열 재귀문과 메모이제이션이 궁금하다면 5번으로 이동해주세요.
- 해당 문제의 경우 DP의 탑다운 방식을 사용했으며 메모이제이션 재귀문을 통해 해결했다.
- N번째 피보나치 수를 구하는 문제로 메모이제이션 함수를 선언하여 해당 N값을 계속해서 fib()라는 재귀문에 입력해준다.
- 이후 해당 메모이제이션 값이 1, 0이 되면 다시 메모이제이션 함수를 선언해준다.
- N이 1인 경우에는 메모이제이션 값이 0, 1이 되고 다시 선언해준다.
- N이 메모이제이션 존재하는 경우 다시 메모이제이션 함수를 선언해준다.
- 위의 경우의 수를 계속해서 선언해주는 방식으로 최종적으로 피보나치 수를 출력해준다.
5. 피보나치 수열과 재귀 함수, 메모이제이션에 대해
1. 피보나치 수열
수학 개념으로 피보나치 수는 첫째 또는 둘쨰 항이 1이고 그 뒤의 모든 항은 바로 앞 두 항의 합인 수열을 말한다.
-
0번째 항부터 시작하는 경우 F(0) = 0 F(1) = 1 F(2) = F(1) + F(0) = 2 F(n) = F(n-1) + F(n-2)
-
1번째 항부터 시작하는 경우 F(1) = F(2) = 1 F(n) = F(n-1) + F(n-2)
- 피보나치 수열 재귀문
def fib(n): if n == 1: return 1 if n == 2: return 1 else: return fib(n-1) + fib(n-2)
- 재귀함수로 자기 자신을 재귀호출하는 함수이다. 수학의 점화식과 비슷한 형태로 코드를 작성할 수 있어 가독성이 높으나 연산 효율이 낮아서 메모리관점에서 그닥 좋지않은 방식이다.
- 이는 반복문과 같은 걸로 피보나치 수가 높아질수록 연산 효율이 급격하게 떨어진다는 단점을 지니고 있다.
- 피보나치 수열 재귀 함수 + 메모이제이션
def fib(N, mem): if N == 0: mem[N] = [1, 0] return mem[N] elif N == 1: mem[N] = [0, 1] return mem[N] if N in mem: return mem[N] else: a = fib(N -1, mem)[0] + fib(N -2, mem)[0] b = fib(N -1, mem)[1] + fib(N -2, mem)[1] mem[N] = [a,b] return mem[N] def memo(N): # 메모리제이션 함수 선언 mem = {} return fib(N, mem)
- 메모이제이션 말 그대로 메모하는 형식으로 이미 계산한 값은 더 이상 연산하지 않아 불필요한 연산을 제거하여 연산을 효율적으로 한다는 강점을 지니는 방법이다.
- 재귀 함수형태로 만들어져 가독성또한 높은 코드 작성 기법이다.