Dynamic Programing:
Fibonachi Series:
1] Brute Force Recursive Approach
This approach directly implements the mathematical recurrence relation:
F(n)=F(n−1)+F(n−2),F(0)=0, F(1)=1
class Solution {
public:
int fib(int n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
};
Complexity:
Time Complexity: O(2^n)
This happens because for each call, two recursive calls are made,
leading to an exponential number of calls.
Space Complexity: O(n)
The space is used for the recursive call stack.
2] Optimized Recursive Approach with Memoization
The brute-force approach repeatedly recalculates the same values.
Memoization stores already-computed results to avoid redundant
computations.
class Solution {
public:
int fibHelper(int n, vector<int>& dp) {
if (n <= 1) return n;
if (dp[n] != -1) return dp[n];
dp[n] = fibHelper(n - 1, dp) + fibHelper(n - 2, dp);
return dp[n];
}
int fib(int n) {
vector<int> dp(n + 1, -1);
return fibHelper(n, dp);
}
};
Complexity:
Time Complexity: O(n)
Each value is computed only once and stored.
Space Complexity: O(n)
For both the dp array and the recursive stack.
Bottom-Up Dynamic Programming
class Solution {
public:
int fib(int n) {
if (n <= 1) return n;
vector<int> dp(n + 1, 0);
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
};
Complexity:
Time Complexity: O(n)
The loop iterates up to n.
Space Complexity: O(n)
For the dp array
Space-Optimized Iterative Approach
Instead of maintaining a full table, we only keep the last two Fibonacci
numbers to save space.
class Solution {
public:
int fib(int n) {
if (n <= 1) return n;
int prev1 = 0, prev2 = 1;
for (int i = 2; i <= n; i++) {
int current = prev1 + prev2;
prev1 = prev2;
prev2 = current;
}
return prev2;
}
};
Complexity:
Time Complexity: O(n)
The loop iterates up to n.
Space Complexity: O(1)
Only two variables are used to store intermediate results.