最长公共子序列
Views: --
给定两个序列 与 ,最长公共子序列(LCS)是在二者中都按原顺序出现的最长序列。
1. 子序列不是子串
子序列可以跳过元素,但不能改变相对顺序。例如 ACE 是 ABCDE 的子序列,却不是连续子串。若把题目误当成最长公共子串,状态转移会完全不同。
2. 状态定义
令
只看两个前缀的最后一个字符:
- 若 ,可以把这个公共字符接到更短前缀的答案后;
- 若 ,任一公共子序列不可能同时使用这两个末尾字符,至少要舍弃一个。
因此
3. 填表顺序与复杂度
每个格子依赖左、上、左上,按行或按列填表即可。状态数为 ,每格 :
4. 为什么相等时一定能配对
当 时,两个前缀存在一个以该字符结尾的最优公共子序列。若某个最优解没用它,可以在不缩短长度的情况下调整末尾匹配。因此问题缩为两个都去掉末尾后的 LCS,再加 1。
不相等时,最优解至多使用其中一个末尾,所以比较删掉 与删掉 的两个子问题即可。
5. 回溯出具体序列
从 逆向移动:
- 若 ,把该字符加入答案,走到 ;
- 否则走向 值更大的上方或左方;
- 若两者相等,说明可能有多个 LCS,任选一个方向只会得到其中一个。
收集到的字符顺序是反的,最后需要翻转。
6. 一个例子
对
X = ABCBDAB
Y = BDCABA
LCS 长度为 4,BCBA 和 BDAB 都是合法答案。这说明“LCS 的长度唯一”不代表“LCS 序列唯一”。
7. 空间压缩
若只求长度,第 行只依赖第 行,可用两行,把空间降为 。进一步原地更新一行时,要额外保存更新前的左上角值。
但压缩后通常无法直接按整张表回溯序列。若既要低空间又要恢复方案,可以使用 Hirschberg 算法,以 时间和 空间递归恢复。
8. LCS 与编辑问题
若只允许插入和删除,把 变成 的最少操作数为
共同保留 LCS,其余字符从 删除、再向其中插入 的剩余字符即可。允许替换且代价独立时,则应使用最小编辑距离的专门状态。