Start learning free

LESSON 277 OF 410 · RECURSION

Recursive Fibonacci in Python with Time Complexity Analysis

Practice O(2n) Read the full explanation

The Fibonacci numbers, commonly denoted F(n) form a sequence, called the Fibonacci sequence, such that each number is the sum of the two preceding ones, starting from 0 and 1. That is,

F(0) = 0, F(1) = 1
F(n) = F(n - 1) + F(n - 2), for n > 1.

Write a recursive function that given n, returns F(n).

Example 1:

Input: n = 2
Output: 1
Explanation: F(2) = F(1) + F(0) = 1 + 0 = 1.

Example 2:

Input: n = 3
Output: 2
Explanation: F(3) = F(2) + F(1) = 1 + 1 = 2.

Example 3:

Input: n = 4
Output: 3
Explanation: F(4) = F(3) + F(2) = 2 + 1 = 3.

Constraints:
  • 0 <= n <= 30
Note:

Don't worry about the time and space complexities of your algorithm.


Hints:

Inside the function, we should first check the base case: if n is less than 2, then we should return n.

If n >= 2, since F(n) = F(n - 1) + F(n - 2), we should return the sum of the recursive calls for n - 1 and n - 2.
STEP 1 OF 2
    Ctrl + Enter to check

    PYTHON · RECURSION

    Recursive Fibonacci in Python, explained

    Understanding the Problem

    The core challenge of this problem is to compute the nth Fibonacci number using a recursive approach. The Fibonacci sequence is a classic example in computer science and mathematics, often used to teach recursion and dynamic programming.

    Common applications of the Fibonacci sequence include algorithm analysis, financial models, and biological settings like population growth models.

    Potential pitfalls include misunderstanding the base cases and not handling the recursive calls correctly, which can lead to infinite recursion or incorrect results.

    Approach

    To solve this problem, we can start with a naive recursive solution and then discuss its limitations and potential optimizations.

    Naive Recursive Solution

    The naive approach directly translates the mathematical definition of the Fibonacci sequence into a recursive function. However, this approach is not optimal due to its exponential time complexity.

    def fibonacci(n):
        # Base case: if n is less than 2, return n
        if n < 2:
            return n
        # Recursive case: return the sum of the two preceding numbers
        return fibonacci(n - 1) + fibonacci(n - 2)
    

    While this solution is simple and elegant, it has a time complexity of O(2^n), which makes it impractical for large values of n.

    Optimized Solutions

    To improve the efficiency, we can use memoization or an iterative approach.

    Memoization

    Memoization stores the results of expensive function calls and reuses them when the same inputs occur again, reducing the time complexity to O(n).

    def fibonacci_memo(n, memo={}):
        # Base case: if n is less than 2, return n
        if n < 2:
            return n
        # Check if the result is already in the memo dictionary
        if n not in memo:
            # Store the result in the memo dictionary
            memo[n] = fibonacci_memo(n - 1, memo) + fibonacci_memo(n - 2, memo)
        return memo[n]
    

    Iterative Approach

    The iterative approach uses a loop to compute the Fibonacci numbers, which also has a time complexity of O(n) and a space complexity of O(1).

    def fibonacci_iterative(n):
        if n < 2:
            return n
        a, b = 0, 1
        for _ in range(2, n + 1):
            a, b = b, a + b
        return b
    

    Algorithm

    Let's break down the memoization algorithm step-by-step:

    1. Check the base case: if n is less than 2, return n.
    2. Check if the result for n is already in the memo dictionary.
    3. If not, compute the result recursively and store it in the memo dictionary.
    4. Return the result from the memo dictionary.

    Code Implementation

    Here is the Python code for the memoization approach:

    def fibonacci_memo(n, memo={}):
        # Base case: if n is less than 2, return n
        if n < 2:
            return n
        # Check if the result is already in the memo dictionary
        if n not in memo:
            # Store the result in the memo dictionary
            memo[n] = fibonacci_memo(n - 1, memo) + fibonacci_memo(n - 2, memo)
        return memo[n]
    
    # Example usage
    print(fibonacci_memo(2))  # Output: 1
    print(fibonacci_memo(3))  # Output: 2
    print(fibonacci_memo(4))  # Output: 3
    

    Complexity Analysis

    The naive recursive solution has a time complexity of O(2^n) and a space complexity of O(n) due to the call stack.

    The memoization approach reduces the time complexity to O(n) and the space complexity to O(n) due to the memo dictionary.

    The iterative approach also has a time complexity of O(n) but a space complexity of O(1).

    Edge Cases

    Potential edge cases include:

    • n = 0: The function should return 0.
    • n = 1: The function should return 1.
    • n = 30: The function should handle the upper constraint efficiently.

    Testing

    To test the solution comprehensively, include a variety of test cases:

    • Simple cases: n = 0, n = 1, n = 2
    • Medium cases: n = 10, n = 15
    • Edge cases: n = 30
    # Test cases
    print(fibonacci_memo(0))  # Output: 0
    print(fibonacci_memo(1))  # Output: 1
    print(fibonacci_memo(10))  # Output: 55
    print(fibonacci_memo(15))  # Output: 610
    print(fibonacci_memo(30))  # Output: 832040
    

    Thinking and Problem-Solving Tips

    When approaching such problems:

    • Understand the problem statement and constraints thoroughly.
    • Start with a simple, naive solution to grasp the basic idea.
    • Identify the inefficiencies and think about how to optimize them.
    • Consider different approaches and choose the most efficient one.
    • Practice similar problems to improve problem-solving skills.

    Conclusion

    In this blog post, we discussed the problem of computing the nth Fibonacci number using a recursive approach. We explored the naive recursive solution, its limitations, and optimized solutions using memoization and iteration. Understanding and solving such problems is crucial for developing strong problem-solving skills in computer science.

    We encourage readers to practice and explore further to deepen their understanding.

    Additional Resources

    Keep going with PythonAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free