LeetSolve - Level Up Your Coding Skills logo

LeetSolve - Level Up Your Coding Skills

Subscribe
Archives
October 20, 2023

Leetcode 509. How To Compute Fibonacci Number F(n)

Calculating Fibonacci numbers efficiently through dynamic programming techniques.

Problem statement

The Fibonacci numbers make up a sequence denoted as F(n), known as the Fibonacci sequence. Each number in this sequence is the sum of the two preceding numbers, with the sequence starting from 0 and 1. In other words:

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

Your task is to calculate the value of F(n) given an integer 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.

Solution 1: Recursive

Code

#include <iostream>
int fib(int n) {
    if (n <= 1) {
        return n;
    } 
    return fib(n - 1) + fib(n - 2);
}
int main() {
    std::cout << fib(2) << std::endl;
    std::cout << fib(3) << std::endl;
    std::cout << fib(4) << std::endl;
}
Output:
1
2
3

This solution computes the nth Fibonacci number using a recursive approach.

Complexity

The time complexity of this solution is exponential, specifically O(2^n). This is because it repeatedly makes two recursive calls for each n, resulting in an exponential number of function calls and calculations. As n grows larger, the execution time increases significantly.

The space complexity of the given recursive Fibonacci solution is O(n). This space complexity arises from the function call stack when making recursive calls.

When you call the fib function with a value of n, it generates a call stack with a depth of n, as each call to fib leads to two more recursive calls (one for n - 1 and one for n - 2) until n reaches the base cases (0 or 1). The space required to store the function call stack is proportional to the depth of the recursion, which is n.

Therefore, the space complexity is linearly related to the input value n, making it O(n). This can be a concern for large values of n because it could lead to a stack overflow if n is too large.

  • Runtime: O(2^n).
  • Extra space: O(n).

Solution 2: Dynamic programming

#include <iostream>
#include <vector>
int fib(int n) {
    if (n <= 1) {
        return n;
    }
    // store all computed Fibonacci numbers
    std::vector<int> f(n + 1);
    f[0] = 0;
    f[1] = 1;
    for (int i = 2; i <= n; i++) {
        f[i] = f[i - 1] + f[i - 2];
    }
    return f[n];
}
int main() {
    std::cout << fib(2) << std::endl;
    std::cout << fib(3) << std::endl;
    std::cout << fib(4) << std::endl;
}
Output:
1
2
3

This solution uses dynamic programming to avoid redundant calculations by storing and reusing previously computed Fibonacci numbers.

Complexity

  • Runtime: O(n).
  • Extra space: O(n).

Solution 3: Reduce space for dynamic programming

Code

#include <iostream>
int fib(int n) {
    if (n <= 1) {
        return n;
    }
    // store only two previous Fibonacci numbers
    int f0 = 0;
    int f1 = 1;
    for (int i = 2; i <= n; i++) {
        int f2 = f1 + f0;
        // update for next round
        f0 = f1;
        f1 = f2;
    }
    return f1;
}
int main() {
    std::cout << fib(2) << std::endl;
    std::cout << fib(3) << std::endl;
    std::cout << fib(4) << std::endl;
}
Output:
1
2
3

This solution calculates the nth Fibonacci number iteratively using two variables to keep track of the last two Fibonacci numbers.

Complexity

  • Runtime: O(n).
  • Extra space: O(1).

Conclusion

The Fibonacci sequence can be efficiently computed using various techniques, including recursion with memoization, bottom-up dynamic programming, or even optimizing space usage by storing only the necessary previous Fibonacci numbers.

Solutions 2 and 3 demonstrate dynamic programming approaches, where Fibonacci numbers are computed iteratively while storing intermediate results to avoid redundant computations.

Solution 3 further optimizes space usage by only storing the necessary previous Fibonacci numbers, resulting in a space complexity of O(1). Understanding these different approaches and their trade-offs is essential for selecting the most appropriate solution based on the problem constraints and requirements.

Exercise

  • N-th Tribonacci Number.

Thanks for reading!

I hope you enjoyed this content. Don't keep it to yourself! Share it with your network and help each other improve your coding skills and advance your career!

Nhut Nguyen, the author of The Problem Solver's Guide To Coding.

Don't miss what's next. Subscribe to LeetSolve - Level Up Your Coding Skills:
This email brought to you by Buttondown, the easiest way to start and grow your newsletter.