- f(3) = f(2) + f(1);
- f(4) = f(3) + f(2);
关键点:
- 保证无后效性
- 每次局部解均为局部问题的最优解(f(4)即为n=4时的最优解):
- 状态尽量简化,一般一维DP只有一个值,二维DP只有两个值(f(n),f(i, j))
- f(n) = f(n-1) + f(n-2);
- f(1) = 1; f(2) = 2;
或者:
- f(n) = f(n-1) + arr(n)
关键点:
- 函数入参尽量简化,善用返回值「比如基于返回值进行链表的调整、比较f(n)的最小值等」
- 基于上一条,入参简化后,无后效性,每次计算结果均可以固化
- 基于上一条,f(n)固化后,可以使用记忆化搜索「存储中间状态」
- 避免写
f(n+2) = f(n) + f(n+1),因为测试用例设计的刁钻,极易导致 n+2 超出 Integer.MAX_VALUE。
- 动态规划状态会发生转移,状态转义方程基本是:
f(x) = A * f(x - 1)形式,状态转移代码一定要写对
- 动态规划和递归、分治没有根本上的区别(关键看有无最优的子结构)
- 共性:找到重复子问题
- 差异性:最优子结构、中途需要淘汰次优解
- 分治:没有最优子结构,需要把所有的子问题计算并进行合并
- 动态规划:有最优子结构,中途需要淘汰次优解
- 最优子结构 opt[n] = best_of(opt[n-1], opt[n-2], …)
- 储存中间状态:opt[i]
- 状态转移方程或者 DP 方程
- Fib: opt[i] = opt[n-1] + opt[n-2]
- 二维路径:opt[i,j] = opt[i+1][j] + opt[i][j+1] (且判断a[i,j]是否空地)
- 傻递归:O(2^n)
- 递归-记忆化搜索-自顶向下:O(n)
- 循环+自底向上:O(n)
| 题目 | 项目链接 | leetcode | 心得 |
|---|---|---|---|
| 64. 最小路径和* | MinimumPathSum | minimum-path-sum | DP |
| 91. 解码方法 | DecodeWays | decode-ways | DP |
| 221. 最大正方形* | MaximalSquare | maximal-square | DP |
| 621. 任务调度器 | TaskScheduler | task-scheduler | 桶思想 |
| 647. 回文子串 | PalindromicSubstrings | palindromic-substrings | dp、暴力 |
| --困难难度-- | |||
| 矩形区域不超过 K 的最大数值和 | todo | max-sum-of-rectangle-no-larger-than-k |