Applicable scene:
The sub-problems are of the same nature as the original problem
The sub-problems are interrelated (different from the divide and conquer algorithm)
Seeking the optimal solution, the core is exhaustive
Dynamic planning features:
- Overlapping subproblems
- State transition equation (the most critical)
- Optimal substructure
Dynamic program problem-solving framework
- base_case
- Exhaustive state
- State transition
Classic case 1: Fibonacci sequence
f[1] = 1
f[2] = 2
f[n] = f[n-1]+f[n-2] // state transition equation
The Fibonacci number sequence is not an authentic dynamic programming problem, at least not a problem of seeking an optimal solution.
Code implementation-recursion (violent recursion)
/*
斐波那契数列
暴力递归
*/
#include <stdio.h>
#include <stdlib.h>
int fib(int n) {
// base_case
if (n ==1 || n ==2) {
return n;
}
// 递归调用
return fib(n - 1) + fib(n - 2);
}
int main() {
int n = 200;
printf("fib(%d) = %d\n", n, fib(n));
return 0;
}
The recursion method is too inefficient. There are a lot of repetitive calculations, the time complexity is O(2^n), and it is time-consuming.
Code implementation-recursive method (top-down/with memo)
Recurse first from top to bottom, and then backtrack from bottom to top.
/*
斐波那契数列
带备忘录的递归
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int helper(int *memo, int n) {
// base_case
if (n ==1 || n ==2) {
return n;
}
// 备忘录查询
if (memo[n] != 0) return memo[n];
memo[n] = helper(memo, n - 1) + helper(memo, n - 2);
return memo[n];
}
int fib(int n) {
// 备忘录初始化
int *memo = new int[n + 1];
memset(memo, 0, n+1);
// 进行带备忘录的递归
return helper(memo, n);
}
int main() {
int n = 50;
printf("fib(%d) = %d\n", n, fib(n));
return 0;
}
Now every node is only calculated once, so the time complexity is O(n).
Due to an additional new memory allocation. So there is one more space expense, so the space complexity is O(n).
The recursive solution with memo is space for time
Code implementation-iterative method (bottom-up)
/*
斐波那契数列
带备忘录的递归
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int helper(int *memo, int n) {
// base_case
if (n ==1 || n ==2) {
return n;
}
// 备忘录查询
if (memo[n] != 0) return memo[n];
memo[n] = helper(memo, n - 1) + helper(memo, n - 2);
return memo[n];
}
int fib(int n) {
// 备忘录初始化
int *memo = new int[n + 1];
memset(memo, 0, n+1);
// 进行带备忘录的递归
return helper(memo, n);
}
int main() {
int n = 50;
printf("fib(%d) = %d\n", n, fib(n));
return 0;
}