class Solution:
def fib(self, n: int) -> int:
if n <= 1:
return n
return self.fib(n - 1) + self.fib(n - 2)
브루트 포스로는 안 풀릴 것 같지만 이렇게 기본적이 낭ㄹ고리즘으로도 풀리긴 한다.
<피보나치 수 재귀 구현 계산 트리>
class Solution:
dp = collections.defaultdict(int)
def fib(self, n: int) -> int:
if n <= 1:
return n
if self.dp[n]:
return self.df[n]
self.dp[n] = self.fib(n-1) + self.fib(n-2)
return self.dp[n]
다이나믹 프로그래밍의 하향식 풀이로 정리한 것이 바로 이 문제의 메모이제이션 풀이다.
원래의 브루트 포스 풀이와 유사하게 재귀로 계산해 나가지만, 이미 계산한 값은 저장해뒀다가 바로 리턴한다.
fib(5)
일 때, 15번 연산을 진행하던 구조는 메모이젣이션 풀이에서는 9번의 연산만으로 풀이할 수 있게 된다.
한 번 계산한 수는 더 이상 계산하지 않으므로 fib(2)
와 fib(3)
은 한 번만 계산하게 되어 매우 효율적이다.
<피보나치 수 메모이제이션 계산 트리>
class Solution:
dp = collections.defaultdict(int)
def fib(self, n: int) -> int:
self.dp[1] = 1
for i in range(2, n + 1):
self.dp[i] = self.dp[i - 1] + self.dp[i - 2]
return self.dp[n]
상향식 풀이, 즉 타뷸레이션 방식으로 풀이한 코드를 살펴보자.
재귀를 사용하지 않고 반복으로 풀이하며, 작은 값부터 직접 계산한며서 타뷸레이션한다.
class Solution:
def fib(self, n: int) -> int:
x, y = 0, 1
for i in range(0, n):
x, y = y, x + y
return x
앞서 풀이는 dp
라는 딕셔너리에 결과를 차곡차곡 담아 나갔지만 변수는 2개만 있어도 충분하다.
이 경우 앞서 풀이처럼 메소드 바깥에 클래스의 멤버 변수도 선언할 필요가 없기 때문에 코드는 훨씬 더 간결해진다.