The Fibonacci numbers are the numbers in the following integer sequence.
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ……..
In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation
Fn = Fn-1 + Fn-2
with seed valuesÂ
F0 = 0 and F1 = 1.
Given a number n, print n-th Fibonacci Number.Â
Examples:Â
Input : n = 2
Output : 1
Input : n = 9
Output : 34
Write a function int fib(int n) that returns Fn. For example, if n = 0, then fib() should return 0. If n = 1, then it should return 1. For n > 1, it should return Fn-1 + Fn-2
For n = 9
Output:34
The following are different methods to get the nth Fibonacci number.Â
Method 1 (Use recursion)Â
A simple method that is a direct recursive implementation mathematical recurrence relation is given above.
C++
#include <bits/stdc++.h>
using namespace std;
int fib( int n)
{
if (n <= 1)
return n;
return fib(n - 1) + fib(n - 2);
}
int main()
{
int n = 9;
cout << fib(n);
getchar ();
return 0;
}
|
Time Complexity: Exponential, as every function calls two other functions.
If the original recursion tree were to be implemented then this would have been the tree but now for n times the recursion function is called
Original tree for recursion
fib(5)
/ \
fib(4) fib(3)
/ \ / \
fib(3) fib(2) fib(2) fib(1)
/ \ / \ / \
fib(2) fib(1) fib(1) fib(0) fib(1) fib(0)
/ \
fib(1) fib(0)
Optimized tree for recursion for code above
  fib(5)Â
  fib(4)
  fib(3)
  fib(2)
  fib(1)
Extra Space: O(n) if we consider the function call stack size, otherwise O(1).
Method 2: (Use Dynamic Programming)
We can avoid the repeated work done in method 1 by storing the Fibonacci numbers calculated so far.Â
C++
#include<bits/stdc++.h>
using namespace std;
class GFG{
public :
int fib( int n)
{
int f[n + 2];
int i;
f[0] = 0;
f[1] = 1;
for (i = 2; i <= n; i++)
{
f[i] = f[i - 1] + f[i - 2];
}
return f[n];
}
};
int main ()
{
GFG g;
int n = 9;
cout << g.fib(n);
return 0;
}
|
Time complexity: O(n) for given n
Auxiliary space: O(n)
Method 3: (Space Optimized Method 2)
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.Â
C++
#include<bits/stdc++.h>
using namespace std;
int fib( int n)
{
int a = 0, b = 1, c, i;
if ( n == 0)
return a;
for (i = 2; i <= n; i++)
{
c = a + b;
a = b;
b = c;
}
return b;
}
int main()
{
int n = 9;
cout << fib(n);
return 0;
}
|
Time Complexity: O(n)Â
Extra Space: O(1)
Method 4: Using power of the matrix {{1, 1}, {1, 0}}
This is another O(n) that relies on the fact that if we n times multiply the matrix M = {{1,1},{1,0}} to itself (in other words calculate power(M, n)), then we get the (n+1)th Fibonacci number as the element at row and column (0, 0) in the resultant matrix.
The matrix representation gives the following closed expression for the Fibonacci numbers:Â
C++
#include<bits/stdc++.h>
using namespace std;
void multiply( int F[2][2], int M[2][2]);
void power( int F[2][2], int n);
int fib( int n)
{
int F[2][2] = { { 1, 1 }, { 1, 0 } };
if (n == 0)
return 0;
power(F, n - 1);
return F[0][0];
}
void multiply( int F[2][2], int M[2][2])
{
int x = F[0][0] * M[0][0] +
F[0][1] * M[1][0];
int y = F[0][0] * M[0][1] +
F[0][1] * M[1][1];
int z = F[1][0] * M[0][0] +
F[1][1] * M[1][0];
int w = F[1][0] * M[0][1] +
F[1][1] * M[1][1];
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
void power( int F[2][2], int n)
{
int i;
int M[2][2] = { { 1, 1 }, { 1, 0 } };
for (i = 2; i <= n; i++)
multiply(F, M);
}
int main()
{
int n = 9;
cout << " " << fib(n);
return 0;
}
|
Time Complexity: O(n)Â
Extra Space: O(1)Â
Â
Method 5: (Optimized Method 4)
Method 4 can be optimized to work in O(Logn) time complexity. We can do recursive multiplication to get power(M, n) in the previous method (Similar to the optimization done in this post)
C++
#include <bits/stdc++.h>
using namespace std;
void multiply( int F[2][2], int M[2][2]);
void power( int F[2][2], int n);
int fib( int n)
{
int F[2][2] = {{1, 1}, {1, 0}};
if (n == 0)
return 0;
power(F, n - 1);
return F[0][0];
}
void power( int F[2][2], int n)
{
if (n == 0 || n == 1)
return ;
int M[2][2] = {{1, 1}, {1, 0}};
power(F, n / 2);
multiply(F, F);
if (n % 2 != 0)
multiply(F, M);
}
void multiply( int F[2][2], int M[2][2])
{
int x = F[0][0] * M[0][0] + F[0][1] * M[1][0];
int y = F[0][0] * M[0][1] + F[0][1] * M[1][1];
int z = F[1][0] * M[0][0] + F[1][1] * M[1][0];
int w = F[1][0] * M[0][1] + F[1][1] * M[1][1];
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
int main()
{
int n = 9;
cout << fib(9);
getchar ();
return 0;
}
|
Time Complexity: O(Logn)Â
Extra Space: O(Logn) if we consider the function call stack size, otherwise O(1).
Method 6: (O(Log n) Time)
Below is one more interesting recurrence formula that can be used to find n’th Fibonacci Number in O(Log n) time. Â
If n is even then k = n/2:
F(n) = [2*F(k-1) + F(k)]*F(k)
If n is odd then k = (n + 1)/2
F(n) = F(k)*F(k) + F(k-1)*F(k-1)
How does this formula work?Â
The formula can be derived from the above matrix equation.Â
Taking determinant on both sides, we get
(-1)n = Fn+1Fn-1 - Fn2
Moreover, since AnAm = An+m for any square matrix A,
the following identities can be derived (they are obtained
from two different coefficients of the matrix product)
FmFn + Fm-1Fn-1 = Fm+n-1 ---------------------------(1)
By putting n = n+1 in equation(1),
FmFn+1 + Fm-1Fn = Fm+n --------------------------(2)
Putting m = n in equation(1).
F2n-1 = Fn2 + Fn-12
Putting m = n in equation(2)
F2n = (Fn-1 + Fn+1)Fn = (2Fn-1 + Fn)Fn (Source: Wiki) --------
( By putting Fn+1 = Fn + Fn-1 )
To get the formula to be proved, we simply need to do the following
If n is even, we can put k = n/2
If n is odd, we can put k = (n+1)/2
Below is the implementation of the above idea. Â
C++
#include <bits/stdc++.h>
using namespace std;
const int MAX = 1000;
int f[MAX] = {0};
int fib( int n)
{
if (n == 0)
return 0;
if (n == 1 || n == 2)
return (f[n] = 1);
if (f[n])
return f[n];
int k = (n & 1)? (n+1)/2 : n/2;
f[n] = (n & 1)? (fib(k)*fib(k) + fib(k-1)*fib(k-1))
: (2*fib(k-1) + fib(k))*fib(k);
return f[n];
}
int main()
{
int n = 9;
printf ( "%d " , fib(n));
return 0;
}
|
Time complexity: O(Log n), as we divide the problem in half in every recursive call.
Method 7: (Another approach(Using Binet’s formula))
In this method, we directly implement the formula for the nth term in the Fibonacci series.Â
Fn = {[(√5 + 1)/2] ^ n} / √5Â
Note: Above Formula gives correct result only upto for n<71. Because as we move forward from n>=71 , rounding error becomes significantly large . Although , using floor function instead of round function will give correct result for n=71 . But after from n=72 , it also fails.
Example: For N=72 , Correct result is 498454011879264 but above formula gives 498454011879265.
C++
#include<iostream>
#include<cmath>
int fib( int n) {
double phi = (1 + sqrt (5)) / 2;
return round( pow (phi, n) / sqrt (5));
}
int main ()
{
int n = 9;
std::cout << fib(n) << std::endl;
return 0;
}
|
Time Complexity: O(logn), this is because calculating phi^n takes logn time
Auxiliary Space: O(1)
Method 8: DP using memoization(Top down approach)
We can avoid the repeated work done in method 1 by storing the Fibonacci numbers calculated so far. We just need to store all the values in an array.
C++
#include <bits/stdc++.h>
using namespace std;
int dp[10];
int fib( int n)
{
if (n <= 1)
return n;
int first, second;
if (dp[n - 1] != -1)
first = dp[n - 1];
else
first = fib(n - 1);
if (dp[n - 2] != -1)
second = dp[n - 2];
else
second = fib(n - 2);
return dp[n] = first + second;
}
int main()
{
int n = 9;
memset (dp, -1, sizeof (dp));
cout << fib(n);
getchar ();
return 0;
}
|
Share your thoughts in the comments
Please Login to comment...