今天是子序列问题的延续,相对都比较简单。重点一方面是要分清楚与dp[i]对应的子序列是否要以nums[i]结尾,另一方面要判断好两种情况各自对应的dp数组值填充方法。
第1题(LeetCode 1143. 最长公共子序列)相比day 52中第3题(LeetCode 718. 最长重复子数组),子序列不再要求是连续的,剩余地方都与其一样。这一变化反映在定义上,dp[i][j]就变成了text1[0: i - 1]与text2[0: j - 1]的最长公共子序列长度(不用[0 : i]和[0 : j]的理由与之前一致,避免初始化的麻烦)。
对于text1[i - 1]与text2[j - 1]相等的情况,最长公共子序列长度相比没有text1[i - 1]和text2[j - 1]时就要增加一位,所以dp[i][j] = dp[i - 1][j - 1] + 1;而两者不相等时,因为子序列不再必须是连续的,所以此时的最大长度不需要归为1,而是维持之前的最大长度即可,之前的最大长度可能是dp[i - 1][j]或dp[i][j - 1],两者中取较大值。初始化方式、遍历顺序都与上一题一样。
- class Solution {
- public:
- int longestCommonSubsequence(string text1, string text2) {
- vector
int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0)); - for (int i = 1; i <= text1.size(); ++i) {
- for (int j = 1; j <= text2.size(); ++j) {
- if (text1[i - 1] == text2[j - 1]) { // 不是text1[i] == text2[j]
- dp[i][j] = dp[i - 1][j - 1] + 1;
- }
- else {
- dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
- }
- }
- }
- return dp[text1.size()][text2.size()];
- }
- };
实现中需要注意,因为为了初始化的方便而采用了额外多一行、一列的dp矩阵,所以与dp[i][j]对应的是text1[i - 1]和text2[j - 1]是否想等的判断,而不是text1[i]和text2[j]。
第2题(LeetCode 1035. 不相交的线)中,“nums1[i] == nums2[j]”要求相等,“绘制的直线不与任何其他连线(非水平线)相交”要求有序,既相等又有序的要求就跟第1题是完全一样的。所以将这一题中的nums1、nums2分别看作第1题中的text1、text2即可,思路和实现完全一样。
- class Solution {
- public:
- int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
- vector
int>> dp(nums1.size() + 1, vector<int>(nums2.size() + 1, 0)); - for (int i = 1; i <= nums1.size(); ++i) {
- for (int j = 1; j <= nums2.size(); ++j) {
- if (nums1[i - 1] == nums2[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[nums1.size()][nums2.size()];
- }
- };
第3题(LeetCode 53. 最大子序和)在day 31中用贪心方法解决过,这里再用DP尝试。dp数组定义方面,将dp[i]定义为“以nums[i]结尾的连续子数组的最大和”。那么对于nums[i],就有两种选择。第1种是将自己拼接在前面的连续子数组之后,得到新的和dp[i - 1] + nums[i];第2种则是抛弃掉前面的连续子数组,从当前位置重新开始,得到新的和nums[i]。从这两种选择中取较大值作为当前位置的dp数值。而题目所求的“连续子数组的最大和”可能以任意位置的数字结尾,所以要在中途不断记录dp数组的最大值,作为最后的结果返回。
- class Solution {
- public:
- int maxSubArray(vector<int>& nums) {
- int dp[nums.size()];
- dp[0] = nums[0];
- int ans = nums[0]; // nums[0]也可以初始化为INT_MIN
- for (int i = 1; i < nums.size(); ++i) {
- dp[i] = max(dp[i - 1] + nums[i], nums[i]);
- ans = max(ans, dp[i]);
- }
- return ans;
- }
- };