第九章 动态规划 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;
    }
}

总结:

  • 子数组 :求解的就是**连续子序列**
  • 子序列:没有强调的连续,只要是子序列即可
相关推荐
Blossom.11815 分钟前
量子计算在密码学中的应用与挑战:重塑信息安全的未来
人工智能·深度学习·物联网·算法·密码学·量子计算·量子安全
1白天的黑夜119 分钟前
贪心算法-860.柠檬水找零-力扣(LeetCode)
c++·算法·leetcode·贪心算法
搏博27 分钟前
专家系统的基本概念解析——基于《人工智能原理与方法》的深度拓展
人工智能·python·深度学习·算法·机器学习·概率论
yzx99101328 分钟前
决策树随机深林
人工智能·python·算法·决策树·机器学习
Y1nhl1 小时前
力扣hot100_子串_python版本
开发语言·python·算法·leetcode·职场和发展
uhakadotcom1 小时前
过来人给1-3 年技术新人的几点小小的建议,帮助你提升职场竞争力
算法·面试·架构
wuqingshun3141592 小时前
蓝桥杯 16. 密文搜索
c++·算法·职场和发展·蓝桥杯·深度优先
Brookty2 小时前
【数据结构】哈希表
数据结构·算法·哈希算法·散列表
Dovis(誓平步青云)3 小时前
【数据结构】·励志大厂版(复习+刷题):二叉树
c语言·数据结构·经验分享·笔记·学习·算法·学习方法
越城3 小时前
算法效率的钥匙:从大O看复杂度计算 —— C语言数据结构第一讲
c语言·开发语言·数据结构·算法