Skip to content

Day 38


1143.最长公共子序列

体会一下本题和 718. 最长重复子数组的区别

题目链接:https://leetcode.cn/problems/longest-common-subsequence/

文章讲解:https://programmercarl.com/1143.最长公共子序列.html

视频讲解:https://www.bilibili.com/video/BV1ye4y1L7CQ

思路分析

最长重复子数组要求元素间是连续的,然而最长公共子序列元素间是不连续的,所以在递推公式中需要考虑以下情况

(1)如果 text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以 dp[i][j] = dp[i - 1][j - 1] + 1;

(2)如果 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])

二维 dp

java
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
              // 延续最长重复子数组的思路,为了简化初始化的过程,空间初始化时多一个
        int[][] dp = new int[text1.length() + 1][text2.length() + 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[text1.length()][text2.length()];
    }
}

1035.不相交的线

其实本题和 1143.最长公共子序列是一模一样的,大家尝试自己做一做。

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

文章讲解:https://programmercarl.com/1035.不相交的线.html

视频讲解:https://www.bilibili.com/video/BV1h84y1x7MP

思路分析

本题的本质就是求最长公共子序列

如何分析线不能相交

根据题意,是要保证顺序的,也就是说只要公共子序列保证在数组中的相对顺序不变,线就不会相交

二维 dp

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. 最大子序和

这道题我们用贪心做过,这次 再用 dp 来做一遍

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

文章讲解:https://programmercarl.com/0053.最大子序和(动态规划).html

视频讲解:https://www.bilibili.com/video/BV19V4y1F7b5

思路分析

本题就两种情况,要么延续之前的累加,要么以当前遍历元素为新的起点重新开始累加

一维 dp

java
class Solution {
    public int maxSubArray(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int res = nums[0];
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            // 要么延续之前的状态,要么以当前作为新起点重新累加
            dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
            res = Math.max(dp[i], res);
        }
        return res;
    }
}

392.判断子序列

这道题目算是编辑距离问题 的入门题目(毕竟这里只是涉及到减法),慢慢的,后面就要来解决真正的 编辑距离问题了

题目链接:https://leetcode.cn/problems/is-subsequence/

文章讲解:https://programmercarl.com/0392.判断子序列.html

视频讲解:https://www.bilibili.com/video/BV1tv4y1B7ym

思路分析

本题对于给定字符串无需做删除操作,只需要对匹配串做删除操作即可,即无需考虑 dp[i - 1][j]的情况,本质就是求最长公共子序列,如果长度和匹配串长度相等,说明是子序列

二维 dp

java
class Solution {
    public boolean isSubsequence(String s, String t) {
        int[][] dp = new int[s.length() + 1][t.length() + 1];
        // 延续求最长公共子序列的思路
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= t.length(); j++) {
                if (s.charAt(i - 1) == t.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    // 给定字符串无需做删减操作,只需要对匹配串操作,无需考虑 dp[i - 1][j]
                    dp[i][j] = dp[i][j - 1];
                }
            }
        }
        // 最长公共子序列的长度和模式串的长度相同,说明是子序列
        if (dp[s.length()][t.length()] == s.length()) {
            return true;
        } else {
            return false;
        }
    }
}

双指针法(简单)

java
class Solution {
    public boolean isSubsequence(String s, String t) {
        int n = s.length(), m = t.length();
        int i = 0, j = 0;
        while (i < n && j < m) {
            if (s.charAt(i) == t.charAt(j)) {
                i++;
            }
            j++;
        }
        return i == n;
    }
}