LeetCode | C++ 动态规划——1143.最长公共子序列、1035.不相交的线、53. 最大子序和
发布人:shili8
发布时间:2024-12-28 15:27
阅读次数:0
**动态规划系列文章**
在 LeetCode 中,动态规划是解决问题的一种常见方法。它通过分解问题,找到最优解的过程来实现。下面我们将讨论三个经典的问题:1143. 最长公共子序列、1035. 不相交的线和53. 最大子序和。
###1. 最长公共子序列(1143)
**问题描述**
给定两个字符串 `s1` 和 `s2`,找到它们的最长公共子序列(LCS)。 LCS 是两个字符串中共同出现的最大子串。
**动态规划解决方案**
我们可以使用一个二维数组 `dp` 来存储每个位置的最长公共子序列长度。其中 `dp[i][j]` 表示 `s1` 的前 `i` 个字符和 `s2` 的前 `j` 个字符的 LCS 长度。
cppclass Solution { public: string longestCommonSubsequence(string s1, string s2) { int m = s1.size(); int n = s2.size(); // dp[i][j] 表示 s1 的前 i 个字符和 s2 的前 j 个字符的 LCS 长度 vector<vector<int>> dp(m +1, vector<int>(n +1)); for (int i =0; i <= m; ++i) { for (int j =0; j <= n; ++j) { if (i ==0 || j ==0) { // 如果 s1 或 s2 的前面没有字符,则 LCS 长度为0 dp[i][j] =0; } else if (s1[i -1] == s2[j -1]) { // 如果当前位置的字符相同,则 LCS 长度等于上一个位置的 LCS 长度加1 dp[i][j] = dp[i -1][j -1] +1; } else { // 如果当前位置的字符不同,则 LCS 长度取决于两个子串中哪个更长 dp[i][j] = max(dp[i -1][j], dp[i][j -1]); } } } // 从 dp[m][n] 开始,反向构造 LCS string lcs; int i = m, j = n; while (i >0 && j >0) { if (s1[i -1] == s2[j -1]) { lcs.push_back(s1[i -1]); --i, --j; } else if (dp[i -1][j] > dp[i][j -1]) { --i; } else { --j; } } return lcs; } };
###2. 不相交的线(1035)
**问题描述**
给定一个点集 `points`,找到不相交的线段数量。两个线段不相交如果它们没有公共点。
**动态规划解决方案**
我们可以使用一个二维数组 `dp` 来存储每个位置的不相交线段数量。其中 `dp[i][j]` 表示 `points` 的前 `i` 个点和 `points` 的前 `j` 个点之间的不相交线段数量。
cppclass Solution { public: int maxUncrossedLines(vector<int>& points) { int n = points.size(); // dp[i][j] 表示 points 的前 i 个点和 points 的前 j 个点之间的不相交线段数量 vector<vector<int>> dp(n +1, vector<int>(n +1)); for (int i =0; i <= n; ++i) { for (int j =0; j <= n; ++j) { if (i ==0 || j ==0) { // 如果 points 的前面没有点,则不相交线段数量为0 dp[i][j] =0; } else if (points[i -1] == points[j -1]) { // 如果当前位置的点相同,则不相交线段数量等于上一个位置的不相交线段数量加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[n][n]; } };
###3. 最大子序和(53)
**问题描述**
给定一个整数数组 `nums`,找到最大子序列和。最大子序列是连续的且不包含负数的子序列。
**动态规划解决方案**
我们可以使用一个一维数组 `dp` 来存储每个位置的最大子序列和。其中 `dp[i]` 表示 `nums` 的前 `i` 个数字的最大子序列和。
cppclass Solution { public: int maxSubArray(vector<int>& nums) { int n = nums.size(); // dp[i] 表示 nums 的前 i 个数字的最大子序列和 vector<int> dp(n); dp[0] = nums[0]; for (int i =1; i < n; ++i) { if (nums[i] >0) { // 如果当前位置的数字大于0,则最大子序列和等于上一个位置的最大子序列和加上当前位置的数字 dp[i] = max(dp[i -1], nums[i]); } else { // 如果当前位置的数字小于或等于0,则最大子序列和等于上一个位置的最大子序列和 dp[i] = dp[i -1]; } } return *max_element(dp.begin(), dp.end()); } };
以上是三个经典问题的动态规划解决方案。这些解决方案使用二维数组或一维数组来存储每个位置的最优解,并通过递归关系找到最终答案。