求解思路
- 递归 + 记忆化 -> 递推
- 状态的定义:opt[n],dp[n],fib[n]
- 状态的转移方程:opt[n] = best_of(opt[n-1], opt[n-2], opt[n-3] ...)
- 最优子结构
例:斐波拉契数列
递推公式
F[n] = F[n-1] + F[n-2]
普通递归 O(2^n)
int fib(int n) {
return n <= 1 ? n : fib(n - 1) + fib(n - 2);
}
递推 O(n)
int fib2(int n) {
int[] ints = new int[n + 2];
ints[0] = 0;
ints[1] = 1;
for (int i = 2; i <= n; i++) {
ints[i] = ints[i - 1] + ints[i - 2];
}
return ints[n];
}
// 只用三个变量求解,最节省空间
int fib3(int n) {
if (n <= 1) return n;
int a = 0, b = 1, c = 0;
for (int i = 1; i < n; i++) {
c = a + b;
b = c;
a = b;
}
return c;
}
例:爬格子
前方高能
类似这种从 A 走到 B 的,一次只能往下或者往右走一步,紫色块的地方走不通,求一共有多少种走法。
这种题和斐波拉契数列的解法差不多的,再来张灵魂绘画。
由于每次只能往下或者往右走一步,所以 A 到 B 的走法等于 C 到 B 加 D 到 B 的走法之和,而 D 到 B 的走法等于 E + G,C 到 B 等于 E + F ,就这样进入了无限套娃。
递推公式:
opt[i,j] = opt[i-1,j] = opt[i,j-1]
if opt[i,j] = '紫块':
opt[i,j] = 0;
else:
opt[i,j] = opt[i-1,j] = opt[i,j-1]