Fibonacci Number#

Problem statement#

[1]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[2].