1. Fibonacci Series
Fibonacci Number¶
1. Recursion + Memoization - Top Down approach¶
In [1]:
                Copied!
                
                
            def fib_memo(n, dp):
    """
    # 0, 1, 2, 3, 4, 5, 6, 7,  8
    # 0, 1, 1, 2, 3, 5, 8, 13, 21
    """
    # base case
    if n == 0 or n == 1:
        return n
    if dp[n] != -1:
        return dp[n]
    # recurrence relation
    dp[n] = fib_memo(n - 1, dp) + fib_memo(n - 2, dp)
    return dp[n]
def fib_memo(n, dp):
    """
    # 0, 1, 2, 3, 4, 5, 6, 7,  8
    # 0, 1, 1, 2, 3, 5, 8, 13, 21
    """
    # base case
    if n == 0 or n == 1:
        return n
    if dp[n] != -1:
        return dp[n]
    # recurrence relation
    dp[n] = fib_memo(n - 1, dp) + fib_memo(n - 2, dp)
    return dp[n]
    
        In [2]:
                Copied!
                
                
            n = 100
dp = [-1] * (n + 1)
ans = fib_memo(n, dp)
print(ans)
n = 100
dp = [-1] * (n + 1)
ans = fib_memo(n, dp)
print(ans)
    
        354224848179261915075
In [3]:
                Copied!
                
                
            def fib_memo(n):
    """
    # 0, 1, 2, 3, 4, 5, 6, 7,  8
    # 0, 1, 1, 2, 3, 5, 8, 13, 21
    """
    # 1. Create a 1D dp array
    dp = [-1] * (n + 1)
    def solve(n):
        # 1. base case
        if n == 0 or n == 1:
            return n
        # 3. check dp array for result before
        # making a recursive call
        if dp[n] != -1:
            return dp[n]
        # 2. Recursive relation + store result in the dp array
        dp[n] = solve(n - 1) + solve(n - 2)
        return dp[n]
    ans = solve(n)
    return ans
def fib_memo(n):
    """
    # 0, 1, 2, 3, 4, 5, 6, 7,  8
    # 0, 1, 1, 2, 3, 5, 8, 13, 21
    """
    # 1. Create a 1D dp array
    dp = [-1] * (n + 1)
    def solve(n):
        # 1. base case
        if n == 0 or n == 1:
            return n
        # 3. check dp array for result before
        # making a recursive call
        if dp[n] != -1:
            return dp[n]
        # 2. Recursive relation + store result in the dp array
        dp[n] = solve(n - 1) + solve(n - 2)
        return dp[n]
    ans = solve(n)
    return ans
    
        In [4]:
                Copied!
                
                
            n = 100
fib_memo(n)
n = 100
fib_memo(n)
    
        Out[4]:
354224848179261915075
2. Tabulation - Bottom Up approach¶
In [5]:
                Copied!
                
                
            def fib_tab(n, dp):
    """
    # 0, 1, 2, 3, 4, 5, 6, 7,  8
    # 0, 1, 1, 2, 3, 5, 8, 13, 21
    """
    # base case
    if n <= 1:
        return n
    # processing
    # check if you already have the number in dp
    if dp[n] != -1:
        return dp[n]
    # go for bottom-up tabulation
    # using the recurrence relation
    # dp[n] = dp[n-1] + dp[n-2]
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    return dp[n]
def fib_tab(n, dp):
    """
    # 0, 1, 2, 3, 4, 5, 6, 7,  8
    # 0, 1, 1, 2, 3, 5, 8, 13, 21
    """
    # base case
    if n <= 1:
        return n
    # processing
    # check if you already have the number in dp
    if dp[n] != -1:
        return dp[n]
    # go for bottom-up tabulation
    # using the recurrence relation
    # dp[n] = dp[n-1] + dp[n-2]
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    return dp[n]
    
        In [6]:
                Copied!
                
                
            n = 100
# step-1: define dp array
dp = [-1] * (n + 1)
# step-2: fill this using the base case
dp[0] = 0
dp[1] = 1
ans = fib_tab(n, dp)
print(ans)
n = 100
# step-1: define dp array
dp = [-1] * (n + 1)
# step-2: fill this using the base case
dp[0] = 0
dp[1] = 1
ans = fib_tab(n, dp)
print(ans)
    
        354224848179261915075
In [7]:
                Copied!
                
                
            def fib_tab(n):
    if n <= 1:
        return n
    # 1. create a 1D dp array
    dp = [-1] * (n + 1)
    # 2. base case(s)
    dp[0] = 0
    dp[1] = 1
    # this is not needed
    # as we are building our solution bottom-up
    # if dp[n] != -1:
    #     return dp[n]
    # 3. build dp array bottom-up using for loop
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    return dp[n]
def fib_tab(n):
    if n <= 1:
        return n
    # 1. create a 1D dp array
    dp = [-1] * (n + 1)
    # 2. base case(s)
    dp[0] = 0
    dp[1] = 1
    # this is not needed
    # as we are building our solution bottom-up
    # if dp[n] != -1:
    #     return dp[n]
    # 3. build dp array bottom-up using for loop
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    return dp[n]
    
        In [8]:
                Copied!
                
                
            fib_tab(100)
fib_tab(100)
    
        Out[8]:
354224848179261915075
3. Space Optimization¶
In [9]:
                Copied!
                
                
            def fib_space_opt(n):
    """
    # 0, 1, 2, 3, 4, 5, 6, 7,  8
    # 0, 1, 1, 2, 3, 5, 8, 13, 21
    """
    # base case
    if n <= 1:
        return n
    prev1 = 0
    prev2 = 1
    for i in range(2, n + 1):
        current = prev1 + prev2
        # shift
        prev1 = prev2
        prev2 = current
        # print(f"current: {current}")
        # print(f"prev1: {prev1}")
        # print(f"prev2: {prev2}")
        # print()
    return current
def fib_space_opt(n):
    """
    # 0, 1, 2, 3, 4, 5, 6, 7,  8
    # 0, 1, 1, 2, 3, 5, 8, 13, 21
    """
    # base case
    if n <= 1:
        return n
    prev1 = 0
    prev2 = 1
    for i in range(2, n + 1):
        current = prev1 + prev2
        # shift
        prev1 = prev2
        prev2 = current
        # print(f"current: {current}")
        # print(f"prev1: {prev1}")
        # print(f"prev2: {prev2}")
        # print()
    return current
    
        In [10]:
                Copied!
                
                
            n = 100
ans = fib_space_opt(n)
print(f"ans: {ans}")
n = 100
ans = fib_space_opt(n)
print(f"ans: {ans}")
    
        ans: 354224848179261915075
In [11]:
                Copied!
                
                
            def fib_tab_space_opt(n):
    if n <= 1:
        return n
    prev1 = 1
    prev2 = 0
    for i in range(2, n + 1):
        current = prev1 + prev2
        prev2 = prev1
        prev1 = current
    return prev1
def fib_tab_space_opt(n):
    if n <= 1:
        return n
    prev1 = 1
    prev2 = 0
    for i in range(2, n + 1):
        current = prev1 + prev2
        prev2 = prev1
        prev1 = current
    return prev1
    
        In [12]:
                Copied!
                
                
            n = 100
fib_tab_space_opt(n)
n = 100
fib_tab_space_opt(n)
    
        Out[12]:
354224848179261915075
In [ ]:
                Copied!