动态规划
动规的五部曲:
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
509.斐波那契数列
70.爬楼梯
746.使用最小花费爬楼梯
62.不同路径
63.不同路径II
343.整数拆分
96.不同的二叉搜索树
本轮树可以分为当1,2,3…n当根节点时,有左子树形式*右子树形式种形式,然后相加
K46.携带研究材料
01背包问题
-
dp[i][j]代表从0-i中挑选物品放到j大小的背包里最大的value 行是物品,列是背包大小。
注意dp数组的大小,dp[m][n+1] -
转化为一维数组时,先遍历物品,再遍历包的大小,对于包大小的遍历应该从大到小,避免重复放进物品。
416.分割等和子集
转化为01背包问题,只需要检查能不能拼凑到sum/2大的背包即可,value和weight都是数值
494.目标和
转化为01背包问题,left-right=target,注意如果(sum + target) % 2 == 1证明不可以分割成这样的子集,target绝对值大于sum也不可以。
dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法
递推公式:构成dp[i]的元素包括dp[i-nums[i]],所以dp[j] += dp[j-nums[i]]
初始化:dp[0]=1,如果等于0则全都是0,1可以理解为{0}里找0有1种方法。
474.一和零
计算1和0的数量,从两个维度做动态规划,需要注意递推公式
int[][] dp = new int[m+1][n+1]; // 最多有i个0和j个1的strs最大子集的大小为dp[i][j]
K52.完全背包
在完全背包遍历背包大小时可以从小到大遍历,因为物品是可重复的,且for循环嵌套顺序不重要。
518.零钱兑换II
完全背包,递推公式和494一样道理
377.组合总和IV
注意题意是不同顺序算不同的情况,所以遍历时应该先遍历背包,再遍历物品,因为如果先物品再背包就没有(3,1)的情况。
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
57.爬楼梯
完全背包
322.零钱兑换
注意初始化,由于每次选的是min,因此初始化必须为MAX_VALUE,但dp[0]为0
在递推时需要注明只有dp[j-coins[i]] != Integer.MAX_VALUE时计算才有意义
279.完全平方数
easy
139.单词拆分
dp[i]表示s从0到i的子串是否可以由数组元素组成
boolean数组默认值为false
每次需要判定从j到i的子串是不是存在于字典中,且dp[j]为true
56.携带矿石资源
多重背包问题,可以转化为01背包,在遍历背包之后嵌套一层物品数量的循环,则递推公式转化为:
dp[j] = Math.max(dp[j], dp[j - k*weight[i]]+k*value[i]);
198.打家劫舍
难点在递推公式
- 如果要偷i,则dp[i-2]+nums[i]
- 如果不偷i,考虑dp[i-1]
213.打家劫舍II
环形,可以考虑两种情况的动态规划,即不考虑第一间房和不考虑最后一间房
然后选最大值即可
337.打家劫舍III
采用后序遍历,计算不偷当前节点和偷当前节点的两种情况下,孩子的选择,注意返回值用数组,下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱
121.买卖股票的最佳时机
dp[i][0]:第i天持有股票手里的钱
dp[i][1]:第i天不持有股票手里的钱
递推公式很好想
122.买卖股票的最佳时机II
和之前不一样的是股票可以多次买卖,因此在dp[i][0]的递推中需要加入前一天已经拥有的利润
123.买卖股票的最佳时机III
可以设置每天的四种状态设计递推公式:第一次拥有,第一次不拥有,第二次拥有,第二次不拥有
124.买卖股票的最佳时机IV
根据上一题的思想创建dp[prices.length][2*k+1]大小的数组,发现奇偶数之间的规律创建递推公式
309.买卖股票的最佳时期含冷冻期
需要设置四个状态计算递推公式: 0.持有股票,1.保持卖出股票状态,2.今天卖出股票,3.今天冷冻期
注意每个递推公式推导的时候思考全面前一天是什么样子可以导致今天的结果
300.最长递增子序列
dp数组表示最后一位是i时最长子序列的长度
674.最长连续递增序列
dp和上一题意义相同,注意题目是最长连续,上题不要求连续
718.最长重复子数组
两个数组进行对比,注意二维数组dp初始化的时候需要处理第一行和第一列,而不是只有00、01、10三个。
1143.最长公共子序列
注意本题的dp含义。
dp[i][j]:长度为[0, i]的字符串text1与长度为[0, j]的字符串text2的最长公共子序列为dp[i][j]
还要注意初始化时,相等是等于1而不是加1,因为此时只对比一个text[0]的值。
1035.不相交的线
本质上和寻找最长公共子序列相同。
53.最大子数组和
贪心√动态规划√
记录最大和,每一轮最大和都和dp[i]比较
注意递推公式不是选择dp[i-1],而是nums[i],和dp[i-1] + nums[i]进行比较
392.判断子序列
差不多
115.不同的子序列
dp[i][j]含义:s中0 ~ i-1在t中0 ~ j-1子串中的出现次数
!!!递推公式(小难):
st当前遍历元素相等:次数 = (采用此时的相等)上个st字母匹配的出现次数 + (不采用此时的相等)s的上个字母和t的本字母匹配的次数(比如bag,bagg不用g做匹配)
st当前元素不相等:上个s字母匹配次数
583.两个字符串的删除操作
dp表示达到相等需要删除的数量
和前几题类似,需要注意初始化的时候不能是0
72.编辑距离
和上题类似,注意不相等时的递推公式:w1删+w2删+w1改
dp[i-1][j]+1, dp[i][j-1], dp[i-1][j-1]+1
674.回文子串
dp表示i~j之间是不是回文子串(j>i)
注意从递归公式推断遍历顺序
516.最长回文子序列
注意序列,可以不连续
返回值与之前的不同,应该是遍历的最后一个。