代码随想录算法训练营第五十三天 | 1143.最长公共子序列 、1035.不相交的线、53. 最大子序和
1143.最长公共子序列
题目链接:1143. 最长公共子序列 - 力扣(LeetCode)
class Solution {public int longestCommonSubsequence(String text1, String text2) {int len1 = text1.length();int len2= text2.length();// dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j], 与718不同// 相对于718.最长重复子数组,718要求子数组是连续的,所以一旦不相同就要重新计算dp(dp = 0);// 但是本题子序列可以是不连续的,所以就算当前不相同,也要往前看是否有相同的int[][] dp = new int[len1 + 1][len2 + 1];for (int i = 1 ; i <= text1.length() ; i++) {char char1 = text1.charAt(i - 1);for (int j = 1; j <= text2.length(); j++) {char char2 = text2.charAt(j - 1);if (char1 == char2) { // 开始列出状态转移方程dp[i][j] = dp[i - 1][j - 1] + 1;} else {// 因为题目不要求连续,可以继承之前的最大值dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);}}}return dp[len1][len2];}
}/**
解释一、
当char1不等于char2的时候,已经取了max(dp【i-1】【j】, dp【i】【j-1】),是实时更新到最大结果的,因为题目不要求是连续的,所以不管char1等不等于char2,每次dp【i】【j】的结果都是实时更新到最大的结果。
第718题,跟这个很类似,但是因为题目要求是连续的,所以在遇到num1不等于num2的时候,不能把之前的结果用来更新。如果采用这道题实时更新的话,比如【0,1,3】和【1, 0, 3】。
遇到3 = 3的时候,就等于 1 + 1 = 2了,因为【0,1,3】和【1,0】这里的最长递增子序列为1。这样做没有考虑是否连续,所以和本题不一样。解释二、
上一题以i-1和j-1是因为子数组必须要求是连续的,如果不连续,公共子数组直接归零,下一个子数组不能继承前一个子数组的公共子数组长度。子序列则不一样,允许中间有间隔,下一个子序列可以继承前一个子序列的公共子序列长度。
这样说很抽象,我们举个例子。比如说两个数组nums1 = 【1,2,3,4,5】 , nums2 = 【1,2,3,8,5】 。在index=3的时候出现分歧了,如果是公共子数组,到index=3时,其公共子数组必须要归零,如果不归零,会影响index=4的判断。
而如果是公共子序列,index=3可以保留index=2的最长子序列数,继而在index=4时继续递增,主要问题就在于,如果你想要这个又要的递推公式dp【i】【j】 = dp【i-1】【j-1】 + 1 就必须这样定义,你当然也可以用上一题的方式定义这一题,或者用这一题的方式定义上一题,但你就需要一个非常麻烦的递推公式 */
1035.不相交的线
题目链接:1035. 不相交的线 - 力扣(LeetCode)
理解成最长公共子序列,一模一样
class Solution {public int maxUncrossedLines(int[] nums1, int[] nums2) {int len1 = nums1.length;int len2 = nums2.length;int[][] dp = new int[len1 + 1][len2 + 1];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] = Math.max(dp[i-1][j], dp[i][j-1]);}}}return dp[len1][len2];}
}
53. 最大子序和
题目链接:53. 最大子数组和 - 力扣(LeetCode)
// 贪心:保证当前区间的count一定大于0,同时更新maxSum,否则舍去count(设置count = 0)
class Solution {public int maxSubArray(int[] nums) {int count = 0;int maxSum = Integer.MIN_VALUE;for(int num : nums) {count += num;maxSum = Math.max(count, maxSum);if(count < 0) {count = 0;}}return maxSum;}
}// DP
class Solution {public int maxSubArray(int[] nums) {int[] dp = new int[nums.length];int maxSum = nums[0];dp[0] = nums[0];for(int i = 1; i < nums.length; ++i) {// 类似于贪心一样,如果dp[i-1]小于0,则舍弃dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);maxSum = Math.max(maxSum, dp[i]);}return maxSum;}
}