图解题库 / 动态规划 · LCS

1143. 最长公共子序列

中等 含交互动画

学完这道你应该能: 说清它为什么用「LCS」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

题目描述

求两个字符串的最长公共子序列长度(顺序一致、可不连续)。

text1 = "abc"
text2 = "ac"
输出 = 2 ("ac")

思路解析

两种情况:当前两个字符相等 → 等于「都去掉这个字符」的 dp[i-1][j-1] + 1;不相等 → 取「去掉其一」的 max(dp[i-1][j], dp[i][j-1])。

建表 · 边界 0:行和列各多一行「空串」。任一方是空串,LCS 必为 0,所以第一行第一列全填 0。

a vs a · 相等:text1 的 a 和 text2 的 a 相等:取左上角 + 1 = 1。

a vs c · 不等:a 和 c 不相等:取上面和左边的较大值,得 1。

b 行 · 都不等:b 这一行,和 a、c 都不相等,每格都取 max(上,左),一直保持 1。

c vs a · 不等:c 和 a 不等,dp[3][1] = max(上1, 左0) = 1。

c vs c · 相等 ⭐:c 和 c 相等:左上角 dp[2][1]=1 再 +1 = 2。

答案 = 右下角:右下角 dp[3][2] = 2 就是答案("ac")。

两个序列比对的题都是这套二维 DP:最长重复子数组、编辑距离、不相交的线。

参考代码(Python)

Python
1dp = [[0]*(n+1) for _ in range(m+1)]   # 多一行一列空串
2for i in range(1, m+1):
3    for j in range(1, n+1):
4        if text1[i-1] == text2[j-1]:      # 字符相等
5            dp[i][j] = dp[i-1][j-1] + 1   # 左上 +1
6        else:                             # 不等
7            dp[i][j] = max(dp[i-1][j], dp[i][j-1])  # 上、左取大
8return dp[m][n]

复杂度分析

  • 时间复杂度:O(m×n) —— 填满表格
  • 空间复杂度:O(m×n) —— 二维表;可压成两行

套路模板

记住骨架:多一行一列空串、相等取左上+1、不等取上左较大。把这两条转移改一改,编辑距离、最长重复子数组、不相交的线全是它。

Python
1# 凡是「两个序列比对」的题都套这个骨架
2dp = [[0]*(n+1) for _ in range(m+1)]   # 多一行一列空串
3for i in range(1, m+1):
4    for j in range(1, n+1):
5        if A[i-1] == B[j-1]:           # 相等
6            dp[i][j] = dp[i-1][j-1] + 1
7        else:                          # 不等
8            dp[i][j] = max(dp[i-1][j], dp[i][j-1])
9return dp[m][n]

易错点

  • 字符下标用 dp[i][j] 的 i,j → ✅ 用 text1[i-1]、text2[j-1](dp 多了「空串」那一行一列,要错开 1)
  • 不等时写成左上 → ✅ 不等取 max(上, 左)(只有相等才能用左上 +1)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →139. 单词拆分 ← 返回题库