「代码随想录算法训练营」第三十八天 | 动态规划 part11
1143. 最长公共子序列
题目链接:https://leetcode.cn/problems/longest-common-subsequence/
文章讲解:https://programmercarl.com/1143.最长公共子序列.html
题目难度:中等
视频讲解:https://www.bilibili.com/video/BV1ye4y1L7CQ
题目状态:有点思路,但细节有点混乱
思路:
维护一个二维动规数组dp[i][j],用来记录长度为i-1的字符串text1与长度为j-1的字符串text2的最长公共子序列,它的更新条件如下:
- 若
text1[i - 1] == text2[j - 1]
,则dp[i][j] = dp[i - 1][j - 1] + 1
; - 若
text1[i - 1] != text2[j - 1]
,则dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
。
其中为什么是i-1和j-1,这个问题和上一题是一样的。
代码:
class Solution { public: int longestCommonSubsequence(string text1, string text2) { int len1 = text1.size(); int len2 = text2.size(); vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0)); for(int i = 1; i <= len1; ++i) { for(int j = 1; j <= len2; ++j) { 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]); } } return dp[len1][len2]; } };
1035. 不相交的线
题目链接:https://leetcode.cn/problems/uncrossed-lines/
文章讲解:https://programmercarl.com/1035.不相交的线.html
题目难度:中等
视频讲解:https://www.bilibili.com/video/BV1h84y1x7MP
题目状态:看题解
思路:
其本质就是寻找最长公共子序列,也就是上一题。
代码:
class Solution { public: int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) { int len1 = nums1.size(); int len2 = nums2.size(); vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0)); for(int i = 1; i <= len1; ++i) { for(int j = 1; j <= len2; ++j) { if(nums1[i - 1] == nums2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]); } } return dp[len1][len2]; } };
53. 最大子数组和
题目链接:https://leetcode.cn/problems/maximum-subarray/
文章讲解:https://programmercarl.com/0053.最大子序和(动态规划).html
题目难度:中等
视频讲解:https://www.bilibili.com/video/BV19V4y1F7b5
题目状态:之前使用其他方法AC过
思路一:贪心算法
遍历整体数组,记录当前总和count
,若count
出现了负数,说明前面这些数组都可以删掉,从下一个元素开始重新遍历,最终返回最大的count
值。
代码一:
class Solution { public: int maxSubArray(vector<int>& nums) { int count = 0; int res = INT_MIN; for(int i = 0; i < nums.size(); ++i) { count += nums[i]; if(count > res) res = count; if(count <= 0) count = 0; } return res; } };
思路二:动态规划
维护一个一维动规数组dp[i]
表示以i
元素结尾的最大值(注意是以i
元素结尾的,而并不是整体的最大值,整体最大值还需要再去遍历)。
代码二:
class Solution { public: int maxSubArray(vector<int>& nums) { if(nums.size() == 0) return 0; vector<int> dp(nums.size()); dp[0] = nums[0]; int maxSum = dp[0]; for(int i = 1; i < nums.size(); ++i) { dp[i] = max(nums[i], dp[i - 1] + nums[i]); maxSum = max(maxSum, dp[i]); } return maxSum; } };
392. 判断子序列
题目链接:https://leetcode.cn/problems/is-subsequence/
文章讲解:https://programmercarl.com/0392.判断子序列.html
题目难度:简单
视频讲解:https://www.bilibili.com/video/BV1tv4y1B7ym/
题目状态:使用其他方式通过,没有使用动规
思路一:
使用两个指针i
和j
分别遍历题目中的序列s
和t
,若遇到s[i] == t[j]
,则i++
,最后判断i
的位置,如果i
最后的位置是序列s
的末尾,表示s
遍历完了,也就是说在t
中找到了所有的s
。
代码一:
class Solution { public: bool isSubsequence(string s, string t) { if(s.empty()) return true; if(t.empty()) return false; int i = 0, j = 0; while(i < s.size() && j < t.size()) { if(s[i] == t[j]) i++; j++; } return i == s.size(); } };
思路二:动态规划
维持一个二维动规数组dp[i][j]
表示在序列s
遍历到i - 1
,序列t
遍历到j - 1
时,这两者的相同子序列的长度。
- 当
s[i - 1] == t[j - 1]
时,动规数组将在前面的基础上加1 - 当两者不相等的时候,动规数组维持原状
代码二:
class Solution { public: bool isSubsequence(string s, string t) { int sLen = s.size(); int tLen = t.size(); vector<vector<int>> dp(sLen + 1, vector<int>(tLen + 1, 0)); for(int i = 1; i <= sLen; ++i) { for(int j = 1; j <= tLen; ++j) { if(s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = dp[i][j - 1]; } } if(dp[sLen][tLen] == sLen) return true; else return false; } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?