Dynamic Programming: Fibonacci Numbers
Introduction
Dynamic Programming is an efficient algorithm design technique used to solve problems by breaking them down into smaller subproblems. It stores the results of these subproblems to avoid redundant work.
Naive Recursion Algorithm for Fibonacci Numbers
def fib_naive(n):
if n <= 2:
return 1
else:
return fib_naive(n - 1) + fib_naive(n - 2)
Memoized Algorithm
def fib_memo(n, memo=None):
if memo is None: memo = {}
if n in memo: return memo[n]
if n <= 2: result = 1
else: result = fib_memo(n - 1, memo) + fib_memo(n - 2, memo)
memo[n] = result
return result
Bottom-Up DP | Time: O(n), Space: O(1)
def fib_bottom_up_O1(n):
if n <= 2: return 1
prev, curr = 1, 1
for k in range(2, n):
prev, curr = curr, prev + curr
return curr
Bottom-Up DP | Time: O(n), Space: O(n)
def fib_bottom_up_On(n):
if n == 1: return [1]
if n == 2: return [1, 1]
fib = [0] * n
fib[0], fib[1] = 1, 1
for k in range(2, n):
fib[k] = fib[k - 1] + fib[k - 2]
return fib