第九章 动态规划 part14 1143. 最长公共子序列 1035. 不相交的线 53. 最大子序和

第五十六天| 第九章 动态规划 part14 1143. 最长公共子序列 1035. 不相交的线 53. 最大子序和

一、1143. 最长公共子序列

  • 题目链接:

  • 题目介绍:

  • 思路:

    • 本题和"最长重复子数组"区别在于**这里不要求是连续的了,但要有相对顺序**,即:"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

    • dp五部曲:

      • (1)确定dp数组及下标含义:

        复制代码
          dp[i][j]:表示的是以下标i-1为结尾的text1和以下标j-1为结尾的text2的最长公共子序列的长度
      • (2)确定递推公式:

        复制代码
          本题不再要求连续,因此dp[i][j]可以由三个方向推出
        复制代码
          如果text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;
        
          如果text1[i - 1] 与 text2[j - 1]不相同,那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的。
        
          即:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
      • (3)初始化dp数组:

        复制代码
          根据dp数组的含义,char1[0, i-1]和空数组的公共子序列长度为0;同理,char2[0, j-1]和空数组的公共子序列长度也为0。因此,dp[i][0] = 0,dp[0][j] = 0。其他位置在后续均可以覆盖,因此都初始化为0。
      • (4)确定遍历顺序:

        • 根据递推公式可知是正序
    • 和重复子数组(连续公共子序列)不同,本题的最终结果是在二维dp数组的最右下角,因为根据递推公式,如果不相同还是会根据左边的和上边的推导出来。

  • 代码:

java 复制代码
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        char[] char1 = text1.toCharArray();
        char[] char2 = text2.toCharArray();
        // (1)确定dp数组及下标含义
        // dp[i][j]:表示的是以下标i-1为结尾的text1和以下标j-1为结尾的text2的最长公共子序列的长度
        int[][] dp = new int[char1.length + 1][char2.length + 1];
        // (3)初始化dp数组
        // 根据dp数组的含义,char1[0, i-1]和空数组的公共子序列长度为0;同理,char2[0, j-1]和空数组的公共子序列长度也为0。因此,dp[i][0] = 0,dp[0][j] = 0。其他位置在后续均可以覆盖,因此都初始化为0。
        // (4)确定遍历顺序
        // 根据递推公式可知是正序
        for (int i = 1; i <= char1.length; i++) {
            for (int j = 1; j <= char2.length; j++) {
                // (2)确定递推公式
        		// 本题不再要求连续,因此dp[i][j]可以由三个方向推出
                if (char1[i-1] == char2[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]);
                }
            }
        }
        // 和重复子数组(连续公共子序列)不同,本题的最终结果是在二维dp数组的最右下角,因为根据递推公式,如果不相同还是会根据左边的和上边的推导出来。
        return dp[char1.length][char2.length];
    }
}

二、1035. 不相交的线

  • 题目链接:https://leetcode.cn/problems/uncrossed-lines/

  • 题目介绍:

    • 在两条独立的水平线上按给定的顺序写下 nums1nums2 中的整数。

      现在,可以绘制一些连接两个数字 nums1[i]nums2[j] 的直线,这些直线需要同时满足满足:

      • nums1[i] == nums2[j]
      • 且绘制的直线不与任何其他连线(非水平线)相交。

      请注意,连线即使在端点也不能相交:每个数字只能属于一条连线。

      以这种方法绘制线条,并返回可以绘制的最大连线数。

      示例 1:

      复制代码
      输入:nums1 = [1,4,2], nums2 = [1,2,4]
      输出:2
      解释:可以画出两条不交叉的线,如上图所示。 
      但无法画出第三条不相交的直线,因为从 nums1[1]=4 到 nums2[2]=4 的直线将与从 nums1[2]=2 到 nums2[1]=2 的直线相交。
  • 思路:

    • 套壳的"最长公共子序列"
    • 思路和解法与上道题目是一样的
  • 代码:

java 复制代码
class Solution {
    public int maxUncrossedLines(int[] nums1, int[] nums2) {
        int[][] dp = new int[nums1.length + 1][nums2.length + 1];
        for (int i = 1; i <= nums1.length; i++) {
            for (int j = 1; j <= nums2.length; 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[nums1.length][nums2.length];
    }
}

三、53. 最大子序和

  • 题目链接:https://leetcode.cn/problems/maximum-subarray

  • 题目介绍:

    • 相关企业

      给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

      子数组 是数组中的一个连续部分。

      示例 1:

      复制代码
      输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
      输出:6
      解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
  • 思路:

    • dp五部曲:

      • (1)确定dp数组及下标含义

        复制代码
          dp[i]:表示的是以nums[i]为结尾的最大连续子序列之和
      • (2)确定递推公式

        复制代码
          dp[i]只能由两个方向推出来:
          	一个是:因为是连续的所以是dp[i-1] + nums[i]
          	另一个是:当前nums[i]
      • (3)初始化dp数组

        复制代码
          dp[0]:表示的是以nums[0]为结尾的最大连续子序列的和,所以dp[0] = nums[0]
      • (4)遍历顺序:正序

  • 代码:

java 复制代码
class Solution {
    public int maxSubArray(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        int result = nums[0];
        // (1)确定dp数组及下标含义
        // dp[i]:表示的是以nums[i]为结尾的最大连续子序列之和
        int[] dp = new int[nums.length];
        // (3)初始化dp数组
        // dp[0]:表示的是以nums[0]为结尾的最大连续子序列的和,所以dp[0] = nums[0].
        dp[0] = nums[0];
        // (4)遍历顺序:正序
        for (int i = 1; i < nums.length; i++) {
            // (2)确定递推公式
            // dp[i]只能由两个方向推出来:
            //     一个是:因为是连续的所以是dp[i-1] + nums[i]
            //     另一个是:当前nums[i]
            dp[i] = Math.max(dp[i-1] + nums[i], nums[i]);
            if (dp[i] > result) result = dp[i];
        }
        return result;
    }
}

总结:

  • 子数组 :求解的就是**连续子序列**
  • 子序列:没有强调的连续,只要是子序列即可
相关推荐
碧海银沙音频科技研究院42 分钟前
ES7243E ADC模拟音频转i2S到 BES I2S1 Master输出播放到SPK精准分析
人工智能·算法·音视频
百度智能云1 小时前
MySQL最怕的IN大列表,被百度智能云GaiaDB治好了!查询速度提升60倍!
算法
信奥卷王1 小时前
[GESP202506 五级] 奖品兑换
数据结构·算法
奶茶树1 小时前
【数据结构】二叉搜索树
数据结构·算法
晨曦(zxr_0102)2 小时前
CSP-X 2024 复赛编程题全解(B4104+B4105+B4106+B4107)
数据结构·c++·算法
ai安歌2 小时前
【Rust编程:从新手到大师】 Rust 控制流深度详解
开发语言·算法·rust
Shinom1ya_2 小时前
算法 day 36
算法
·白小白2 小时前
力扣(LeetCode) ——15.三数之和(C++)
c++·算法·leetcode
海琴烟Sunshine2 小时前
leetcode 268. 丢失的数字 python
python·算法·leetcode
CL.LIANG2 小时前
视觉SLAM前置知识:相机模型
数码相机·算法