跳转至

1143. 最长公共子序列

原题链接

题目描述

给定两个字符串 \(text1\) 和 \(text2\),返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 \(0\)

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

  • 例如,"ace""abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • \(1\) \(≤\) \(text1.length, text2.length\) \(≤\) \(1000\)
  • \(text1\) 和 \(text2\) 仅由小写英文字符组成。

算法与思路

动态规划   \(O(n^2)\)

状态 \(dp[i][j]\)

  • 定义:\(test1\) 的前 \(i\) 个字母 和 \(test2\) 的前 \(j\) 个字母 的组成的公共子序列的集合。

  • 属性:子序列长度的最大值。

状态转移:

  • \(test1[i] ≠ test2[j]\)

    1. \(test1[i]\) 不包含在最长公共子序列中;
    2. \(test2[j]\) 不包含在最长公共子序列中。

    根据状态的定义,可以得出\(a\)情况可以用 \(dp[i - 1][j]\) 的状态表示;同理,\(b\)情况可以用 \(dp[i][j - 1]\) 的状态表示。

  • \(test1[i] = test2[j]\)

    可以由 \(dp[i - 1][j - 1] + 1\) 来表示。

最后可以根据状态的定义,可以得知,\(dp[n][m]\) 为最终答案。

复杂度分析:

时间复杂度:\(O(nm)\) 。每次计算一个 \(test1\) 的字符,就要遍历一遍 \(test2\) 的所有字符。

空间复杂度:\(O(nm)\) 。需要 \(n\)\(m\) 列的 \(dp\) 数组来存储状态。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int dp[1010][1010];
        memset(dp, 0, sizeof dp);

        int n = text1.size(), m = text2.size();
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                if (text1[i - 1] == text2[j - 1])
                    dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
            }

        return dp[n][m];
    }
};
回到页面顶部