1143. 最长公共子序列(Longest Common Subsequence)M

英文题目

  • Given two strings text1 and text2, return the length of their longest common subsequence. If there is no common subsequence, return 0.

  • A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.

  • For example, "ace" is a subsequence of "abcde".

  • A common subsequence of two strings is a subsequence that is common to both strings.

  • Example 1:

  • Input: text1 = "abcde", text2 = "ace" 
    Output: 3  
    Explanation: The longest common subsequence is "ace" and its length is 3.
    
  • Example 2:

  • Input: text1 = "abc", text2 = "abc"
    Output: 3
    Explanation: The longest common subsequence is "abc" and its length is 3.
    
  • Example 3:

  • Input: text1 = "abc", text2 = "def"
    Output: 0
    Explanation: There is no such common subsequence, so the result is 0.
    
  • Constraints:

  • 1 <= text1.length, text2.length <= 1000

  • text1 and text2 consist of only lowercase English characters.

中文题目

  • 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。

  • 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

  • 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。

  • 若这两个字符串没有公共子序列,则返回 0。

  • 示例 1:

  • 输入:text1 = "abcde", text2 = "ace" 
    输出:3  
    解释:最长公共子序列是 "ace",它的长度为 3。
    
  • 示例 2:

  • 输入:text1 = "abc", text2 = "abc"
    输出:3
    解释:最长公共子序列是 "abc",它的长度为 3。
    
  • 示例 3:

  • 输入:text1 = "abc", text2 = "def"
    输出:0
    解释:两个字符串没有公共子序列,返回 0。
    
  • 提示:

  • 1 <= text1.length <= 1000

  • 1 <= text2.length <= 1000

  • 输入的字符串只含有小写英文字符。

动态规划

  • dp[i][j]表示字符串 A 的 i 号位和 B 的 j 号位之前的LCS长度(下标从0开始)

  • 有两种情况:

  • 1.若A[i]==B[j],则字符串A与字符串B的LCS增加了1位,既有dp[i+1][j+1] = dp[i][j]+1

  • 2.若A[i]!=B[j],则字符串A的i号位无法延长,因此dp[i+1][j+1]将会继承dp[i][j+1]与dp[i+1][j]中的较大值

  • 状态转移方程:

  • 边界:

  • 时间复杂度:O(mn),空间复杂度:O(mn)

    # python3: 时间 652 ms, 击败 92.38%; 内存 40.9 MB, 击败 41.15%
    class Solution:
        def longestCommonSubsequence(self, text1: str, text2: str) -> int:
            l1, l2 = len(text1), len(text2)
            dp = [[0] * (l2+1) for _ in range(l1+1)]
            for i in range(l1):
                for j in range(l2):
                    if text1[i] == text2[j]:
                        dp[i+1][j+1] = dp[i][j] + 1
                    else:
                        dp[i+1][j+1] = max(dp[i+1][j], dp[i][j+1])
            return dp[l1][l2]
    
    // c++: 时间 52 ms, 击败 69.53%; 内存 24 MB, 击败 9.45%
    class Solution {
    public:
        int longestCommonSubsequence(string text1, string text2) {
            int l1 = text1.size(), l2 = text2.size();
            vector<vector<int>> dp((l1+1), vector<int>((l2+1), 0));
            for (int i = 0; i < l1; ++i) {
                for (int j = 0; j < l2; ++j) {
                    if (text1[i] == text2[j]) {
                        dp[i+1][j+1] = dp[i][j] + 1;
                    } else {
                        dp[i+1][j+1] = max(dp[i+1][j], dp[i][j+1]);
                    }
                }
            }
            return dp[l1][l2];
        }
    };
    
    // java: 时间 18 ms, 击败 69.39%; 内存 47.3 MB, 击败 70.11%
    class Solution {
        public int longestCommonSubsequence(String text1, String text2) {
            int l1 = text1.length(), l2 = text2.length();
            int[][] dp = new int[l1+1][l2+1];
            for (int i = 0; i < l1; ++i) {
                for (int j = 0; j < l2; ++j) {
                    if (text1.charAt(i) == text2.charAt(j)) {
                        dp[i+1][j+1] = dp[i][j] + 1;
                    } else {
                        dp[i+1][j+1] = Math.max(dp[i+1][j], dp[i][j+1]);
                    }
                }
            }
            return dp[l1][l2];
        }
    }
    
    // go: 
    func longestCommonSubsequence(text1 string, text2 string) int {
        l1, l2 := len(text1), len(text2)
        dp := make([][]int, l1+1)
        for i := 0; i < l1+1; i++ {
            dp[i] = make([]int, l2+1)
        }
        for i := 0; i < l1; i++ {
            for j := 0; j < l2; j++ {
                if text1[i] == text2[j] {
                    dp[i+1][j+1] = dp[i][j] + 1
                } else {
                    dp[i+1][j+1] = maxInt(dp[i+1][j], dp[i][j+1])
                }
            }
        }
        return dp[l1][l2];
    }
    
    func maxInt(i, j int) int {
        if i > j {
            return i
        }
        return j
    }
    
    // javascript: 时间 128 ms, 击败 33.27%; 内存 67.7 MB, 击败 59.8%
    /**
     * @param {string} text1
     * @param {string} text2
     * @return {number}
     */
    var longestCommonSubsequence = function(text1, text2) {
        const l1 = text1.length, l2 = text2.length;
        const dp = new Array(l1+1).fill(0).map(() => new Array(l2+1).fill(0));
        for (let i = 0; i < l1; ++i) {
            for (let j = 0; j < l2; ++j) {
                if (text1.charAt(i) == text2.charAt(j)) {
                    dp[i+1][j+1] = dp[i][j] + 1;
                } else {
                    dp[i+1][j+1] = Math.max(dp[i+1][j], dp[i][j+1]);
                }
            }
        }
        return dp[l1][l2];
    };
    
Last Updated:
Contributors: Shiqi Lu