基础
刷题
- 最长公共子序列
一维dp数组比较复杂,这里看到二维dp数组更简单
动规五部曲:
- 确定dp数组含义
dp[i][j] 代表 以text1[i-1]结尾的字符串text1[0:i] 和 以text2[j-1]结尾的字符串text2[0:j]的最长公共不连续子序列
- 确定dp数组递推公式
if text1[i-1] == text2[j-1] {
dp[i][j] = dp[i-1][j-1] + 1
}else {
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
// 这里记录前面的最大公共子序列
}
- 确定dp数组初始化
dp[0][j] = 0
dp[i][0] = 0
- 确定dp数组遍历顺序
从左到右,从上到下
- 打印dp数组
- 不相交的线
这里不相交的线就是求最长公共子序列,我的解法中使用result获取最大的dp值,其实不需要,直接取dp[len(nums1)][len(nums2)] 就可以,因为如果nums1[len(nums1)-1] 和 nums2[len(nums2)-1] 相等就是最大值,不等就找dp[len(nums1)-1][len(nums2)] 和 dp[len(nums1)][len(nums2)-1] 中的最大值,这才是使用动态规划的意义
- 最大子数组和
动规五部曲:
- 确定dp数组含义
dp[i] 是以nums[i]为结尾的最大连续子数组和(必须使用dp[i],因为题目子数组必须是连续的,所以递归到i+1的时候才能使用dp[i]的值)
- 确定dp数组递推公式
dp[i] = max(dp[i-1]+nums[i], nums[i])
// 因为必须使用nums[i],所以只有两种情况
- 确定dp数组初始化
dp[0] = nums[0]
- 确定dp数组遍历顺序
从左到右
- 打印dp数组
- 判断子序列
这道题可以使用双指针来解答,参考第一个,其实不需要dp
这里讲一下动态规划的方法:
动规五部曲:
- 确定dp数组含义
dp[i][j] 是以s[i-1]为结尾的字符串和以t[j-1]为结尾的字符串的子序列的最大长度
- 确定dp数组递推公式
if s[i-1] == t[j-1] {
dp[i][j] = dp[i-1][j-1] + 1
}else {
dp[i][j] = dp[i][j-1]
// 这里因为题目是判断s是否为t的子序列
// s作为子序列,只能删除t中的元素,也就是dp[i][j-1]
}
- 确定dp数组初始化
dp[i][0] = 0
dp[0][j] = 0
- 确定dp数组遍历顺序
从左到右
从上到下
- 打印dp数组
总结
技巧:
- 对于需要匹配结尾元素的题目或者需要寻找一种最佳方案的题目,需要找到最后一组匹配的样本数据,并在dp数组中把他保存下来,因为他的值就是结果,参考53. 最大子数组和,减少其他情况干预
- 动态规划需要倒推公式,需要想完成最后一步需要哪些元素,组合起来就是dp数组的递推公式
- 少写一维dp数组,能写二维就写二维的,最好可以从二维转化为一维