DP के साथ Fibonacci
In this page:
def fib(n):
if n <= 1:
return n
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b
Fibonacci DP
Plain recursive Fibonacci वही छोटी Fibonacci values बार-बार recompute करता है, इसलिए इसका running time exponentially बढ़ता है; हर value को पहली बार compute होने पर store करना उसी recursion को एक fast, DP-powered version में बदल देता है।
उदाहरण: Fibonacci DP
#include <iostream>
using namespace std;
int main() {
int dp[11]; dp[0]=0; dp[1]=1;
for (int i = 2; i <= 10; i++) dp[i] = dp[i-1] + dp[i-2];
cout << "Stored values turn exponential recursion into fib(10) = " << dp[10] << " in linear time";
return 0;
}
public class Main {
public static void main(String[] args) {
int[] dp = new int[11]; dp[0]=0; dp[1]=1;
for (int i = 2; i <= 10; i++) dp[i] = dp[i-1] + dp[i-2];
System.out.println("Stored values turn exponential recursion into fib(10) = " + dp[10] + " in linear time");
}
}
dp = [0]*11
dp[1] = 1
for i in range(2, 11):
dp[i] = dp[i-1] + dp[i-2]
print(f"Stored values turn exponential recursion into fib(10) = {dp[10]} in linear time")
#include <stdio.h>
int main() {
int dp[11]; dp[0]=0; dp[1]=1;
for (int i = 2; i <= 10; i++) dp[i] = dp[i-1] + dp[i-2];
printf("Stored values turn exponential recursion into fib(10) = %d in linear time", dp[10]);
return 0;
}
Login to try C/C++/Java code in the editor
Space Optimization
चूंकि fib(n) compute करने के लिए सिर्फ इससे ठीक पहले वाली दो values चाहिए, आपको पूरी table store करने की ज़रूरत नहीं — बस दो running variables रखना और हर step उन्हें update करना memory को O(n) से O(1) तक घटाता है।
उदाहरण: Space Optimization
#include <iostream>
using namespace std;
int main() {
int prev2 = 0, prev1 = 1;
for (int i = 2; i <= 10; i++) { int cur = prev1 + prev2; prev2 = prev1; prev1 = cur; }
cout << "Only 2 variables needed, fib(10) = " << prev1;
return 0;
}
public class Main {
public static void main(String[] args) {
int prev2 = 0, prev1 = 1;
for (int i = 2; i <= 10; i++) { int cur = prev1 + prev2; prev2 = prev1; prev1 = cur; }
System.out.println("Only 2 variables needed, fib(10) = " + prev1);
}
}
prev2, prev1 = 0, 1
for i in range(2, 11):
prev2, prev1 = prev1, prev1 + prev2
print("Only 2 variables needed, fib(10) =", prev1)
#include <stdio.h>
int main() {
int prev2 = 0, prev1 = 1;
for (int i = 2; i <= 10; i++) { int cur = prev1 + prev2; prev2 = prev1; prev1 = cur; }
printf("Only 2 variables needed, fib(10) = %d", prev1);
return 0;
}
Login to try C/C++/Java code in the editor
Memoization
एक memoized version natural top-down recursive structure रखता है (fib(n), fib(n-1) और fib(n-2) को call करता है) लेकिन पहले एक cache जांचता है, इसलिए n की हर distinct value सिर्फ एक बार compute होती है चाहे यह कितनी भी बार request की जाए।
उदाहरण: Memoization
#include <iostream>
#include <unordered_map>
using namespace std;
unordered_map<int,int> cache;
int fib(int n) {
if (n <= 1) return n;
if (cache.count(n)) return cache[n];
return cache[n] = fib(n-1) + fib(n-2);
}
int main() { cout << "Recursive shape kept, fib(10) = " << fib(10); return 0; }
import java.util.*;
public class Main {
static Map<Integer,Integer> cache = new HashMap<>();
static int fib(int n) {
if (n <= 1) return n;
if (cache.containsKey(n)) return cache.get(n);
int r = fib(n-1) + fib(n-2);
cache.put(n, r);
return r;
}
public static void main(String[] args) { System.out.println("Recursive shape kept, fib(10) = " + fib(10)); }
}
cache = {}
def fib(n):
if n <= 1:
return n
if n in cache:
return cache[n]
cache[n] = fib(n-1) + fib(n-2)
return cache[n]
print("Recursive shape kept, fib(10) =", fib(10))
#include <stdio.h>
int cache[11]={0}, computed[11]={0};
int fib(int n) {
if (n <= 1) return n;
if (computed[n]) return cache[n];
computed[n] = 1;
return cache[n] = fib(n-1) + fib(n-2);
}
int main() { printf("Recursive shape kept, fib(10) = %d", fib(10)); return 0; }
Login to try C/C++/Java code in the editor
Complexity
Results store करना naive recursion के exponential time को linear time में बदल देता है, क्योंकि n distinct subproblems में से हर एक अब हर branching recursive call में recompute होने के बजाय बिल्कुल एक बार solve होता है।
उदाहरण: Complexity
#include <iostream>
using namespace std;
int main() {
cout << "Naive recursion: O(2^n); DP (memo or tabulation): O(n), each subproblem solved once";
return 0;
}
public class Main {
public static void main(String[] args) {
System.out.println("Naive recursion: O(2^n); DP (memo or tabulation): O(n), each subproblem solved once");
}
}
print("Naive recursion: O(2^n); DP (memo or tabulation): O(n), each subproblem solved once")
#include <stdio.h>
int main() {
printf("Naive recursion: O(2^n); DP (memo or tabulation): O(n), each subproblem solved once");
return 0;
}
Login to try C/C++/Java code in the editor
Practice
Fibonacci आमतौर पर पहला DP example सिखाया जाता है क्योंकि इसके overlapping subproblems recursion tree में सीधे देखना आसान है, इसे harder problems से निपटने से पहले यह समझने का एक clean तरीका बनाते हुए कि memoization और tabulation क्यों मदद करते हैं।
उदाहरण: Practice
#include <iostream>
using namespace std;
int main() {
cout << "Fibonacci's recursion tree makes overlapping subproblems easy to see -- the classic first DP example";
return 0;
}
public class Main {
public static void main(String[] args) {
System.out.println("Fibonacci's recursion tree makes overlapping subproblems easy to see -- the classic first DP example");
}
}
print("Fibonacci's recursion tree makes overlapping subproblems easy to see -- the classic first DP example")
#include <stdio.h>
int main() {
printf("Fibonacci's recursion tree makes overlapping subproblems easy to see -- the classic first DP example");
return 0;
}
Login to try C/C++/Java code in the editor
- बिना किसी cache के plain recursive
fib(n - 1) + fib(n - 2)लिखना, जो exponential है। - Base cases गलत पाना, जैसे
dp[1] = 0। fib(n)के लिए हर value store करना जब सिर्फ पिछली दो चाहिए, memory waste करते हुए।
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first: