leetcode-zgd-day53-1143.最长公共子序列/1035.不相交的线/53.最大子数组和/小结

126 阅读3分钟

1143.最长公共子序列

题目链接:1143. 最长公共子序列 - 力扣(Leetcode)

解题思路:

 class Solution {
     public int longestCommonSubsequence(String text1, String text2) {
         /**
          * 1.dp[i][j] test1 0-i字符 test2 0-j字符  的最长公共子序列
          * 2.if(test1.charAt(i) == test2.charAt(j)) dp[i][j] = dp[i - 1][j  - 1] + 1;
          * else dp[i][j] = Math.max(dp[i, j - 1],dp[i - 1][j]);
          * 3.初始化
          */
         int[][] dp = new int[text1.length()][text2.length()];
         int rcd = 0;
         char c2 = text2.charAt(0);
         for (int i = 0; i < text1.length(); i++) {
             if(c2 == text1.charAt(i) && rcd == 0) rcd = 1;
             dp[i][0] = rcd;
         }
         rcd = 0;
         char c1 = text1.charAt(0);
         for (int j = 0; j < text2.length(); j++) {
             if (c1 == text2.charAt(j) && rcd == 0) rcd = 1;
             dp[0][j] = rcd;
         }
         for(int i = 1; i < text1.length(); i++){
             for(int j = 1; j < text2.length(); j++){
                 if(text1.charAt(i) == text2.charAt(j)) dp[i][j] = dp[i - 1][j  - 1] + 1;
                 else dp[i][j] = Math.max(dp[i][j - 1],dp[i - 1][j]);
             }
         }
         return dp[text1.length() - 1][text2.length() - 1];
     }
 }

1035.不相交的线

题目链接:1035. 不相交的线 - 力扣(Leetcode)

解题思路:这个题就是最长公共子序列的一个变种。

 class Solution {
     public int maxUncrossedLines(int[] nums1, int[] nums2) {
         /**
          * 1.dp[i][j] 以nums1 0-i这段数组和nums2 0-j这段数组的最多不相交的线
          * 2.if(nums1[i] == nums2[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
          *   else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
          * 3.从第一次匹配的位置为分割点,前面是0,后面是1
          */
         int[][] dp = new int[nums1.length][nums2.length];
         int rcd = 0;
         for(int i = 0; i < nums1.length; i++){
             if(rcd == 0 && nums1[i] == nums2[0]) rcd = 1;
             dp[i][0] = rcd;
         }
         rcd = 0;
         for(int i = 0; i < nums2.length; i++){
             if(rcd == 0 && nums2[i] == nums1[0]) rcd = 1;
             dp[0][i] = rcd;
         }
         for(int i = 1; i < nums1.length; i++){
             for(int j = 1; j < nums2.length; j++){
                 if(nums1[i] == nums2[j]) 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[nums1.length - 1][nums2.length - 1];
     }
 }

53.最大子数组和

题目链接:53. 最大子数组和 - 力扣(Leetcode)

解题思路:

因为本题目要求是最大和的连续子数组,所以,dp数组应该定义为以元素i为结尾的连续子数组的最大和

然后再通过一个ans记录从0-i元素结尾的各个最大和的最大和。

 class Solution {
     public int maxSubArray(int[] nums) {
         /**
          * 1.dp[i] 以元素i结尾的具有最大和的连续子数组
          * 两种可能,以起始点区分开,1.起始点就是i 2.起始点不是i
          * 2.dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);
          * 3.dp[0] = nums[0]
          */
         int[] dp = new int[nums.length];
         int ans = nums[0];
         dp[0] = nums[0];
         for(int i = 1; i < nums.length; i++){
             dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);
             ans = Math.max(ans, dp[i]);
         }
         return ans;
     }
 }

总结

这种公共子序列和公共子数组题目的dp数组定义可以分为两类

一类是需要子数组或者子序列连续,一类不要求子数组和子序列连续

如果要求连续,就类似53题这样,以每个元素为结尾去定义dp数组,然后求这么多种情况中的极值。

 /**
 * 1.dp[i] 以元素i结尾的具有最大和的连续子数组
 * 两种可能,以起始点区分开,1.起始点就是i 2.起始点不是i
 * 2.dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);
 * 3.dp[0] = nums[0]
 */

如果不要求连续,就以例如如下方式去定义dp。结果就是dp的最后推出来的元素。就不需要求极值了。

 /**
 * 1.dp[i][j] 以nums1 0-i这段数组和nums2 0-j这段数组的最多不相交的线
 * 2.if(nums1[i] == nums2[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
 *   else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
 * 3.从第一次匹配的位置为分割点,前面是0,后面是1
 */