Table of Contents generated with DocToc
将大规范的问题转换成小规模的问题,并且缓存中间结果。 动态规范 = 分治递归 + 记忆存储
leetcode原题:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法。
动态规划有几个典型特征,最优子结构、状态转移方程、边界、重叠子问题。在青蛙跳阶问题中:
- f(n-1)和f(n-2) 称为 f(n) 的最优子结构
- f(n)= f(n-1)+f(n-2)就称为状态转移方程
- f(1) = 1, f(2) = 2 就是边界啦
- 比如f(10)= f(9)+f(8),f(9) = f(8) + f(7) ,f(8)就是重叠子问题。
动态规划的思路:
- 穷举分析
- 确定边界
- 找出规律,确定最优子结构
- 写出状态转移方程
如果一个问题,可以把所有可能的答案穷举出来,并且穷举出来后,发现存在重叠子问题,就可以考虑使用动态规划。
-
DP 状态机:往往是强调某一个阶段和上一个阶段之间的联系,且一个阶段里面有多种状态(比如说“有”和“无”)。
-
树形 DP
1 编辑距离
dfs(i,j)=
- s[i]=s[j]: dfs[i-1,j-1]
- s[i]!=s[j]: min(dfs(i,j-1),dfs(i-1,j),dfs(i-1,j-1))+1
- 子数组/子串 subarray/substring 连续
- 子序列 subsequence 非连续
![](.04_dynamic_programming_images/Longest Common Subsequence.png)
s: 第一个字符串, 长度为 n t: 第二个字符串, 长度为 m
子问题:都选==都不选
dfs[i,j]=
- max(dfs[i-1,j-1]+1) s[i]=t[j]
- max(dfs[i-1,j],dfs[i,j-1]) s[i]!=t[j]
![](.04_dynamic_programming_images/Longest Common Subsequence2.png)
![](.04_dynamic_programming_images/Longest Common Subsequence3.png)
思路一: s 与 s反转后的 LCS(最长公共子序列)
- S1=eacbba
- S2=abbcae
思路二: 从两侧缩小问题规模 ![](.04_dynamic_programming_images/Longest Palindromic Subsequence1.png)
因为 最左e != 最右a:所以不能同时选 ![](.04_dynamic_programming_images/Longest Palindromic Subsequence2.png)
dfs(i,j)=
- dfs(i+1,j-1)+2 s[i]=s[j]
- max(dfs(i+1,j),dfs(i,j-1)) s[i]!=s[j]
递归边界
- 如果剩余一个字母,为回文 dfs(i,i)=1
- 两个字母相同时,比如bb dfs(i,i+1)-->dfs(i+1,i)
监控二叉树
蓝色=min(左蓝,左黄,左红)+min(右蓝,右黄,右红)+1
红色=min(左蓝,右红)+min(右红,右蓝)+min(左蓝,右蓝)
要么n-1台阶上去,要么n-2台阶上去
3 找零钱
- 最多装 capacity, 求最大值 dfs(i,c)=max(dfs(i-1.c),dfs(i-1,c-w[i],v[i])
- 正好装 capacity, 求方案数量 dfs(i,c)=dfs(i-1,c)+dfs(i-1,c-w[i])
- 至少装 capacity, 求最小值 dfs(i,c)=min(dfs(i-1.c),dfs(i-1,c-w[i],v[i])
- dfs(i,c)=max(dfs(i-1.c),dfs(i,c-w[i],v[i])
6 打家劫舍
可以看到 01->2 ,12->3, 32->4, 所以留下归
从后面开始算: dfs[i] = max(dfs(i-1), dfs(i-2)+nums[i])
数组转换--> f[i]=max(f[i-1],f[i-2]+num[i])
因为防止负数 --> f[i+2]=max(f[i+1],f[i]+num[i])
思路一:选 或 不选, 从后面往前
dfs[i]= max{dfs[j}+1 j<i 且 nums[j]<nums[i]
思路三:LIS = nums 与排序去重后 nums 的 LCS
思路四:交换状态与状态值
![](.04_dynamic_programming_images/Longest Palindromic Subsequence3.png) 翻译成递推 f[i][j] =
-
0 i>j
-
1 i=j
-
f[i+1][j-1]+2 s[i]=s[j]
-
max(f[i+1][j],f[i+1][j-1]) s[i]!=s[j]
-
因为需要从 f[i+1]->f[i],所以 i 逆序,
-
因为从 s[i][j-1]->f[i][j], 所以 j 正序
答案是 f[0][n-1]