最长公共子序列

来自GSXAB的知识库
公共子序列
术语名称 公共子序列
英语名称 common subsequence
别名 公共子列
最长公共子序列
术语名称 最长公共子序列
英语名称 longest common subsequence
别名 最长公共子列, LCS

公共子序列(common subsequence),指从一个序列集合中全部元素(通常为 2 个序列)公共的子列

最长公共子序列(longest common subsequence, 缩写 LCS),指从这样集合中全部元素全部公共子列中的最长者。

字符(或其他符号)序列的最长公共子序列是一个经典算法问题。在序列数目任意时,是一个 NP-难问题。当序列数目有限时,可以在多项式时间内通过线性规划方式解决。

本文的主题是“最长公共子序列(longest common subsequence, LCS)问题”而不是“最长公共子串(longest common substring, LCS)问题”。

算法

原理

两个序列 [math]\displaystyle{ X,Y }[/math] 的最长公共子序列 [math]\displaystyle{ LCS(X,Y) }[/math] 有以下性质。

  • 对于某个符号 [math]\displaystyle{ a }[/math] ,通过连接构成序列 [math]\displaystyle{ Xa,Ya }[/math] 必然有 [math]\displaystyle{ LCS(Xa,Ya)=LCS(X,Y)a }[/math] 。可以推广到相同后缀序列。
  • 对于不同的两个符号 [math]\displaystyle{ x\neq y }[/math] ,连接起来的序列 [math]\displaystyle{ Xx,Yy }[/math] 要么其中一个新符号进入公共子序列,要么不起作用,必然有 [math]\displaystyle{ LCS(Xx,Yy)=\max\{LCS(Xx,Y), LCS(X,Yy)\} }[/math]

因此记每个序列 [math]\displaystyle{ X }[/math] 的第 [math]\displaystyle{ n }[/math] 项为 [math]\displaystyle{ x_n }[/math] ,前 [math]\displaystyle{ n }[/math] 项为 [math]\displaystyle{ X_n }[/math] ,则可以获得 LCS 函数的递推形式:

[math]\displaystyle{ LCS(X_i,Y_j) = \begin{cases} \varepsilon &, ij=0 \\ LCS(X_{i-1},Y_{j-1})x_i &, i\gt 0,j\gt 0,x_i=y_i \\ \max\{LCS(X_i,Y_{j-1}), LCS(X_{i-1},Y_j)\} &, i\gt 0,j\gt 0,x_i\neq y_i \\ \end{cases} }[/math]

因此算法可以根据 [math]\displaystyle{ LCS(X_0,Y_0)=\varepsilon }[/math] 的初始状态与 [math]\displaystyle{ i,j }[/math] 两个变量,进行一个二维的动态规划。

伪代码

时间复杂度