最长公共子序列

双序列 DP 经典题:`dp[i][j]` 表示两个前缀的最长公共子序列长度。

#resource / algorithm #type / snippet #status / growing #source / leetcode #algo / dp

[!info] related notes 算法面试题型 MOC 动态规划 网格 DP 与双序列 DP 编辑距离 不同的子序列 最长递增子序列(对比:以 i 结尾 vs 前 i 个)

最长公共子序列

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

题意

给你两个字符串 text1text2,求它们的最长公共子序列长度。

为什么是双序列 DP

每次都在比较两个前缀:

  • text1 的前 i 个字符
  • text2 的前 j 个字符

状态

dp[i][j] 表示 text1 的前 i 个字符与 text2 的前 j 个字符的最长公共子序列长度。

转移

如果最后一个字符相同:

dp[i][j] = dp[i - 1][j - 1] + 1

否则:

dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

边界

任意一个字符串为空时,答案都是 0

样例

text1 = "abcde", text2 = "ace"

最长公共子序列是 ace,长度为 3

JavaScript

var longestCommonSubsequence = function(text1, text2) {
    const m = text1.length;
    const n = text2.length;
    const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));

    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            if (text1[i - 1] === text2[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];
};

易错点

  • ij 是前缀长度,不是字符串下标;访问字符时要用 i - 1j - 1
  • 这题是“前 i 个元素”模型,不是“以 i 结尾”模型
  • 不要和子串(substring)搞混:子序列可以不连续,子串必须连续

空间优化

dp[i][j] 只依赖 dp[i-1][j-1]dp[i-1][j]dp[i][j-1],可以压成一维数组。

注意:内层 j 必须倒序遍历,否则 dp[j-1] 已经被当前行覆盖,不再是上一行的值。

var longestCommonSubsequence = function(text1, text2) {
    const m = text1.length;
    const n = text2.length;
    const dp = new Array(n + 1).fill(0);

    for (let i = 1; i <= m; i++) {
        let prev = 0;
        for (let j = 1; j <= n; j++) {
            const temp = dp[j];
            if (text1[i - 1] === text2[j - 1]) {
                dp[j] = prev + 1;
            } else {
                dp[j] = Math.max(dp[j], dp[j - 1]);
            }
            prev = temp;
        }
    }

    return dp[n];
};

与 LIS 的对比

题目状态定义维度模型
LISdp[i]:以 nums[i] 结尾的最长递增子序列一维以 i 结尾
LCSdp[i][j]:两个前缀的最长公共子序列二维前 i 个元素

LIS 枚举 j < i 转移;LCS 根据当前字符是否相等转移。

同类题

创建于 2026/3/18 更新于 2026/5/27