Start learning free

LESSON 277 OF 410 · RECURSION

Recursive Fibonacci in JavaScript (Time Complexity: Exponential)

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

    JAVASCRIPT · RECURSION

    Recursive Fibonacci in JavaScript, 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 has applications in various fields such as algorithm analysis, financial modeling, and biological settings.

    Potential pitfalls include not handling the base cases correctly and not optimizing the recursive calls, which can lead to excessive computation time for larger values of n.

    Approach

    To solve this problem, we can start with a naive recursive approach:

    • Check the base cases: if n is 0 or 1, return n.
    • For n >= 2, return the sum of the two preceding Fibonacci numbers.

    This naive approach is simple but not optimal due to its exponential time complexity. Each call to the function results in two more calls, leading to a large number of redundant calculations.

    Optimized Solutions

    To optimize, we can use memoization or dynamic programming:

    • Memoization: Store the results of previous calculations in a cache to avoid redundant work.
    • Dynamic Programming: Build the Fibonacci sequence iteratively from the bottom up.

    Algorithm

    Naive Recursive Approach

    /**
     * Naive recursive approach to find the nth Fibonacci number.
     * @param {number} n - The index of the Fibonacci sequence.
     * @return {number} - The nth Fibonacci number.
     */
    function fibonacci(n) {
      // Base cases
      if (n < 2) {
        return n;
      }
      // Recursive case
      return fibonacci(n - 1) + fibonacci(n - 2);
    }
    

    Memoized Recursive Approach

    /**
     * Memoized recursive approach to find the nth Fibonacci number.
     * @param {number} n - The index of the Fibonacci sequence.
     * @param {Object} memo - The cache to store previously computed Fibonacci numbers.
     * @return {number} - The nth Fibonacci number.
     */
    function fibonacciMemo(n, memo = {}) {
      // Base cases
      if (n < 2) {
        return n;
      }
      // Check if result is already in the cache
      if (memo[n]) {
        return memo[n];
      }
      // Compute and store the result in the cache
      memo[n] = fibonacciMemo(n - 1, memo) + fibonacciMemo(n - 2, memo);
      return memo[n];
    }
    

    Dynamic Programming Approach

    /**
     * Dynamic programming approach to find the nth Fibonacci number.
     * @param {number} n - The index of the Fibonacci sequence.
     * @return {number} - The nth Fibonacci number.
     */
    function fibonacciDP(n) {
      if (n < 2) {
        return n;
      }
      const fib = [0, 1];
      for (let i = 2; i <= n; i++) {
        fib[i] = fib[i - 1] + fib[i - 2];
      }
      return fib[n];
    }
    

    Complexity Analysis

    Naive Recursive Approach: Time complexity is O(2^n) due to redundant calculations. Space complexity is O(n) due to the call stack.

    Memoized Recursive Approach: Time complexity is O(n) as each Fibonacci number is computed once. Space complexity is O(n) due to the cache and call stack.

    Dynamic Programming Approach: Time complexity is O(n) as each Fibonacci number is computed once. Space complexity is O(n) due to the array used to store Fibonacci numbers.

    Edge Cases

    Edge cases include:

    • n = 0: Should return 0.
    • n = 1: Should return 1.
    • n = 30: Should handle the upper constraint efficiently.

    Testing

    To test the solution comprehensively, consider the following test cases:

    • fibonacci(0) should return 0.
    • fibonacci(1) should return 1.
    • fibonacci(2) should return 1.
    • fibonacci(3) should return 2.
    • fibonacci(4) should return 3.
    • fibonacci(30) should return 832040.

    Use a testing framework like Jest or Mocha to automate these tests.

    Thinking and Problem-Solving Tips

    When approaching such problems:

    • Understand the problem and constraints thoroughly.
    • Start with a simple solution and then optimize.
    • Use memoization or dynamic programming to avoid redundant calculations.
    • Practice similar problems to improve problem-solving skills.

    Conclusion

    Understanding and solving the Fibonacci sequence problem using recursion helps in grasping fundamental concepts of algorithm design and optimization. Practice and exploration of different approaches are key to mastering such problems.

    Additional Resources

    For further reading and practice:

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