Problem
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,
Sequence is defined as, $$ F_{0} = 0 $$ and $$ F_{1} = 1 $$ and $$ F_{n} = F_{n-1} + F_{n-2} $$
Given n
, calculate F(n)
.
Examples
Example 1:
|
|
Example 2:
|
|
Solution
Video explanation
Here is the video explaining this method in detail. Please check it out:
Method 1 - Use Recursion
A simple method that is a direct recursive implementation mathematical recurrence relation given above.
Code
|
|
|
|
Time Complexity
- Time Complexity: T(n) = T(n-1) + T(n-2) = O(2^n) which is exponential.
- Space complexity: O(1) (assuming recursive stack is okay)
Method 2 - Top Down DP
We can observe that this implementation does a lot of repeated work (see the following recursion tree below, where F(3) and F(2) is calculated twice). So this is a bad implementation for nth Fibonacci number.
Recursion tree for execution of fib(5):
graph TD F5["F(5)"] F5 --> F4["F(4)"]:::blue F5 --> F3["F(3)"]:::green F4 --> F3_1["F(3)"]:::green F4 --> F2["F(2)"]:::orange F3 --> F2_1["F(2)"]:::orange F3 --> F1["F(1)"]:::red F3_1 --> F2_2["F(2)"]:::orange F3_1 --> F1_1["F(1)"]:::red F2 --> F1_2["F(1)"]:::red F2 --> F0["F(0)"]:::purple F2_1 --> F1_3["F(1)"]:::red F2_1 --> F0_1["F(0)"]:::purple F2_2 --> F1_4["F(1)"]:::red F2_2 --> F0_2["F(0)"]:::purple %% Styles for coloring duplicate nodes %% classDef unique fill:#f9f,stroke:#333,stroke-width:2px; classDef blue fill:#87CEEB,stroke:#333,stroke-width:2px; classDef green fill:#90EE90,stroke:#333,stroke-width:2px; classDef orange fill:#FFA07A,stroke:#333,stroke-width:2px; classDef red fill:#FFC0CB,stroke:#333,stroke-width:2px; classDef purple fill:#DDA0DD,stroke:#333,stroke-width:2px;
If you prefer slightly cleaner image:
As we saw above, this problem shows the overlapping subproblems pattern, so let’s make use of memoization here. We can use an array to store the already solved subproblems (see the changes in the highlighted lines).
Code
|
|
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n)
- 🧺 Space complexity:
O(n)
Method 3 - Bottom Up DP
Let’s apply Tabulation to our example of Fibonacci numbers. Since we know that every Fibonacci number is the sum of the two preceding numbers, we can use this fact to populate our table.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n)
, as the loop runs from2
ton
, so the time complexity isO(n)
. - 🧺 Space complexity:
O(n)
as the array (or list) of sizen + 1
is used to store intermediate Fibonacci values, so the space complexity isO(n)
.
Method 4 - Space Optimized DP
We can optimize the space used in method 2 by storing the previous two numbers only because that is all we need to get the next Fibonacci number in series.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n)
due to sequential calculations - 🧺 Space complexity:
O(1)
as we use only 2 variables.
Method 5 - Using power of the matrix
The Fibonacci sequence can be expressed using the following matrix recurrence relation:
$$ \begin{bmatrix} F(n+1) & F(n) \\ F(n) & F(n-1) \end{bmatrix} = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} ^n $$
In simpler terms, the nth Fibonacci number is found in the top-left entry of: $$ \text{Matrix} = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} ^n
$$
Thus, calculating Fibonacci numbers reduces to raising a 2x2 matrix to the power ( n ).
Steps
1. Base Case:
- For ( n = 0 ) ⇨ `F(0) = 0`
- For ( n = 1 ) ⇨ `F(1) = 1`
2. Matrix Representation of the Recurrence Relation:
$$ M = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} $$ and set the initial result matrix ( R ) to the identity matrix:
$$ I = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}
$$
3. Exponentiation with Binary Exponentiation:
Use matrix exponentiation (through binary exponentiation) to raise ( M ) to the power ( n-1 ):
If n
is even, split the exponentiation into smaller powers:
$$
M^n = (M^{n/2}) \cdot (M^{n/2})
$$
if n
is odd:
$$
M^n = M \cdot M^{n-1}
$$
4. Extract the Fibonacci Number: After computing ( M^{n-1} ), the Fibonacci number ( F(n) ) is located at the top-left (0, 0) entry of the resulting matrix.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(log n)
for matrix exponentiation. - 🧺 Space complexity:
O(1)
as we just use extra memory 2x2 matrix, which is constant.
Method 6 - Using Binet’s Formula
Can there be formula for Fibonacci numbers in terms of n? Answer is yes.
The formula is called Binet’s formula. It uses something called golden ratio.
Golden Ratio (φ)
- An irrational number approximately equal to 1.6180339887…
- Can be expressed mathematically as: φ = (1 + √5) / 2
Binet’s Formula
$$ F(n) = \frac{\phi ^ n - \phi ^ {-n}}{\sqrt{5}} $$
Limitations
However, this formula has limitations:
- It involves powers of φ, which is an irrational number. Calculating exact values with an irrational number can be complex, especially for larger n.
- The square root of 5 (√5) is another irrational number, adding further complexity.
Therefore, Binet’s formula is not typically used for practical calculations of Fibonacci numbers due to its reliance on irrational numbers.
Complexity
- ⏰ Time complexity:
O(1)
- 🧺 Space complexity:
O(1)