动态规划
动态规划:
-
特点:核心是状态转移【由许多的重叠子问题组成】,
- 当前状态依赖于上一个状态【递推公式】,
- 其次是初始化【对初始情况进行讨论】
- 遍历顺序:状态的推到方向判断【回文字串】
-
经典题型:
-
基础题型:
- 斐波那契数:递推公式的推导;
- 爬楼的方法:多个状态相互叠加得到下一个状态;
- 爬楼梯的消耗:多个状态相互直接的min,得到下个状态;
- 不同路径:推导公式在题目中,关键点在初始化;
- 不同路径II:有障碍,增加路径判断;
- 整数拆分:贪心更简单,动态规划:拆分为【两个数之和,至少三个数之和】取最大值;
- 不同的二叉搜索树:递推公式的推导,左子树,右子树;
-
背包问题:
-
理论:
- 背包容量:一定;
- 物品
- 体积:物品体积一定;
- 价值:物品价值一定;
- 数量:
- 只有一个:01背包;
- 无数个:完全背包;
- 不同物品,数量不同:多重背包;
- 整体上,分别是背包遍历和物品遍历,一个二维的动态规划;
- 递推公式:
- 初始化:是对物品dp[0][i]进行初始化;
- 遍历顺序:先遍历物品还是先遍历背包都可,先遍历物品更好理解;
- 组合与排列取决于编列的顺序:
- 如果求组合数就是外层for循环遍历物品,内层for遍历背包。【之前状态是,左上角】
- 如果求排列数就是外层for遍历背包,内层for循环遍历物品。【还是有几种方法】
-
01背包:之前的状态【使用的是左上角的值】
- 分割子集,最后一块石头的重量:这两题都是填充背包,递推公式是求max最有价值的值;
- 目标和:是一定能分割,求分割的方法有多少种,递推公式是相加,还有初始化考察点,当物品体积为0的时;
- 1和0:是一个三维的0-1背包问题;
-
完全背包:之前状态【以当前点为角的左上角【不包含当前点】】
-
多重背包:
- 相当于对物品在进行迭代一次【单次取一个,两个,三个...】,转化为01背包问题;
-
总结:
-
背包递推公式:
-
是否能装满,最多能装多少,最大价值,最小个数:
\[dp[j] = (min||max) (dp[j], dp[j - num[i]] + num[i]) \] -
问装满背包有多少种方法:
\[dp[j] = dp[j] + dp[j - num[i]] \] -
遍历顺序:【物品 背包】
- 01背包,完全背包:通常是先物品,在背包【组合】;
- 完全背包:必须先背包,在物品【排列】;
-
细节对于一维dp动态数组:
- 01之前状态:是由当前点的左上矩形状态推导【不包含该点】;【对于物体,得从后向前遍历】;
- 完全背包:是由当前点的左上矩形状态推导【包含该点】;【直接前向遍历】
-
-
-
-
打家劫舍:都是基于数组,循环链表,树,等数据结构,递推公式比较单一,考察在相关状态数,其次在于初始化;
-
股票问题:相当于一个状态下多个节点的相互关系,交织出当前状态,通常分为持节股票节点和不迟有节点【可以交易的最大笔数】,其次初始化和之前状态数相关;
- 从买卖一次到买卖多次【贪心,记录已有的最小值,相互关系】;
- 从最多买卖两次到最多买卖k次【同一个状态下的不同节点】,初始化;
- 从冷冻期再到手续费【之前状态的关系【递推】】,初始化
-
子序列问题:
-
子序列【不连续】
-
最长上升【下降】子序列:是对元素的删除【双层迭代,可以回溯,超时】,dp[i]以num[i]为结尾的子序列长度;‘
-
最长公共子序列:
if (nums[i] == num[j]) { dp[i][j] = dp[i - 1][j - 1] } else { //相对顺序:正上和正左 dp[i][j] = max(dp[i - 1][j - 1],dp[i][j - 1]) } -
不相交的线:同最长公共子序列【两个数组的相对顺序不变下的公共子序列】
-
-
子序列【连续】
-
最长连续上升【下降】序列:单层迭代【可以贪心】;
-
最长公共子数组:【二维动态数组,dp】,以dp[i][j]的是num1[i]和num2[j]的最长子数组;
if (nums[i] == num[j]) { dp[i][j] = dp[i - 1][j - 1] } //有序,是对角线有序, //相对顺序:正上和正左 dp[i][j] = max(dp[i - 1][j - 1],dp[i][j - 1]) -
最大子数组和:可以贪心
-
-
距离编辑
-
判断子序列:两个子序列的并集【相对顺序:正上和正左】;
判断字符串的的包含:KMP算法;
动态规划:拥有初始化,动态数组,并没有双指针性能好;
-
子序列包含的个数:之前是判断能不能,现在是有多少种方案;
-
两个字符串的删除操作:之前是只允许删除一个字符串;
-
距离编辑:
- 对一个字符串的删除,插入,替换;
- 删除:dp[i][j - 1];
- 插入:相当于另一个字符串的删除,dp[i - 1][j];
- 替换:相当于两个字符串都删除:dp[i - 1][j - 1];
关键在于dp的定义,用于简化初始化,
常见操作:删除,插入,替换,
类似于空间换效率,相比回溯方法,将所有可能计算出来,【当前状态依赖于左上角的状态】
- 对一个字符串的删除,插入,替换;
-
-
回文字串题型:
- 回文子串的数量:考察遍历顺序
- 最长回文子序列:在字串的基础上,无需就是正上,正左取最大值;
对于字符串的动态规划:一般分为相不相等,两种情况;
五部曲:
- 确定动态数组dp的含义;
- 确定递推公式【有时候,一个状态下有多个节点,股票】
- dp的初始化【序列,dp的扩大定义,能更好的初始化】,
- 确定遍历顺序【背包问题,顺序关系组合和排序,回文,顺序关系递推公式】
- 举例:当前状态和哪些之前状态相关【正上,正左,斜对角,等等】;
-
-

浙公网安备 33010602011771号