Leetcode1143. 最长公共子序列

解题思路

求两个数组或者字符串的最长公共子序列问题,肯定是要用动态规划的。下面的题解并不难,你肯定能看懂。

首先,区分两个概念:子序列可以是不连续的;子数组(子字符串)需要是连续的;

另外,动态规划也是有套路的:单个数组或者字符串要用动态规划时,可以把动态规划 dpi 定义为 nums0:i 中想要求的结果;当两个数组或者字符串要用动态规划时,可以把动态规划定义成两维的 dpij ,其含义是在 A0:i 与 B0:j 之间匹配得到的想要的结果。

  1. 状态定义

比如对于本题而言,可以定义 dpij 表示 text10:i-1 和 text20:j-1 的最长公共子序列。 (注:text10:i-1 表示的是 text1 的 第 0 个元素到第 i - 1 个元素,两端都包含)

之所以 dpij 的定义不是 text10:i 和 text20:j ,是为了方便当 i = 0 或者 j = 0 的时候,dpij表示的为空字符串和另外一个字符串的匹配,这样 dpij 可以初始化为 0.

  1. 状态转移方程

知道状态定义之后,我们开始写状态转移方程。

当 text1i - 1 == text2j - 1 时,说明两个子字符串的最后一位相等,所以最长公共子序列又增加了 1,所以 dpij = dpi - 1j - 1 + 1;举个例子,比如对于 ac 和 bc 而言,他们的最长公共子序列的长度等于 a 和 b 的最长公共子序列长度 0 + 1 = 1。

当 text1i - 1 != text2j - 1 时,说明两个子字符串的最后一位不相等,那么此时的状态 dpij 应该是 dpi - 1j 和 dpij - 1 的最大值。举个例子,比如对于 ace 和 bc 而言,他们的最长公共子序列的长度等于 ① ace 和 b 的最长公共子序列长度0 与 ② ac 和 bc 的最长公共子序列长度1 的最大值,即 1。

综上状态转移方程为:

dpij=dpi−1j−1+1dpij = dpi - 1j - 1 + 1dpij=dpi−1j−1+1, 当 text1i−1==text2j−1;text1i - 1 == text2j - 1;text1i−1==text2j−1;

dpij=max(dpi−1j,dpij−1)dpij = max(dpi - 1j, dpij - 1)dpij=max(dpi−1j,dpij−1), 当 text1i−1!=text2j−1text1i - 1 != text2j - 1text1i−1!=text2j−1

  1. 状态的初始化

初始化就是要看当 i = 0 与 j = 0 时, dpij 应该取值为多少。

当 i = 0 时,dp0j 表示的是 text1text1text1 中取空字符串 跟 text2text2text2 的最长公共子序列,结果肯定为 0.

当 j = 0 时,dpi0 表示的是 text2text2text2 中取空字符串 跟 text1text1text1 的最长公共子序列,结果肯定为 0.

综上,当 i = 0 或者 j = 0 时,dpij 初始化为 0.

  1. 遍历方向与范围

由于 dpij 依赖与 dpi - 1j - 1 , dpi - 1j, dpij - 1,所以 iii 和 jjj 的遍历顺序肯定是从小到大的。

另外,由于当 iii 和 jjj 取值为 0 的时候,dpij = 0,而 dp 数组本身初始化就是为 0,所以,直接让 iii 和 jjj 从 1 开始遍历。遍历的结束应该是字符串的长度为 len(text1)len(text1)len(text1) 和 len(text2)len(text2)len(text2)。

  1. 最终返回结果

由于 dpij 的含义是 text10:i-1 和 text20:j-1 的最长公共子序列。我们最终希望求的是 text1 和 text2 的最长公共子序列。所以需要返回的结果是 i = len(text1) 并且 j = len(text2) 时的 dplen(text1)len(text2)

代码如下:

java 复制代码
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int m = text1.length();
        int n = text2.length();
        int[][] dp = new int[m+1][n+1];
        for(int i = 1; i <= m;i++){
            for(int j = 1; j <= n;j++){
                if(text1.charAt(i-1) == text2.charAt(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[m][n];

    }
}

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

相关推荐
旖-旎1 天前
《LeetCode 646 最长数对链 || LeetCode 1143 最长公共子序列》
c++·算法·leetcode·动态规划
旖-旎2 天前
《LeetCode647 回文子串 || LeetCode 5 最长回文子串》
c++·算法·leetcode·动态规划·哈希算法
tkevinjd2 天前
力扣300-最长递增子序列
算法·leetcode·职场和发展·动态规划·贪心
学究天人2 天前
数学公理体系大全:第十四章 向量空间与模:线性代数的公理化与推广
线性代数·算法·矩阵·动态规划·抽象代数
星马梦缘3 天前
算法设计 期末复习笔记
算法·动态规划·二分图·最小生成树·线性规划·最大流
学究天人3 天前
数学公理体系大全:第七章 连续统假设与力迫法简介
人工智能·算法·机器学习·数学建模·动态规划·图论·抽象代数
满怀冰雪3 天前
第29篇-状态压缩DP-当状态很多时如何降维优化
java·算法·动态规划
学究天人4 天前
数学公理体系大全:第一章 命题逻辑:真值之舞
人工智能·算法·机器学习·数学建模·动态规划·图论·抽象代数
旖-旎4 天前
《LeetCode 978 最长湍流子数组 || LeetCode 139 单词拆分》
c++·算法·leetcode·动态规划
学究天人4 天前
数学公理体系大全:Comprehensive Collection of Mathematical Axiom Systems(补充卷9)
人工智能·线性代数·算法·数学建模·动态规划·原型模式·抽象代数