📜  DAA-最长公共子序列

📅  最后修改于: 2021-01-12 03:35:20             🧑  作者: Mango


最长的公共子序列问题是找到两个给定字符串中都存在的最长序列。

子序列

让我们考虑序列S = 1 ,s 2 ,s 3 ,s 4 ,…,s n >。

S上的序列Z = 1 ,z 2 ,z 3 ,z 4 ,…,z m >称为S的子序列,当且仅当它可以从某些元素的S缺失中得出。

共同子序列

假设XY是元素的有限集合上的两个序列。我们可以说,ZXY的一个公共子序列,如果Z,XY的子序列。

最长的公共子序列

如果给出一组序列,则最长的公共子序列问题是找到所有序列的最大长度的公共子序列。

最长的常见子序列问题是经典计算机科学问题,它是数据比较程序(例如diff-utility)的基础,并已在生物信息学中得到应用。版本控制系统(例如SVN和Git)也广泛使用它来协调对版本控制的文件集合所做的多个更改。

天真的方法

X为长度为m的序列, Y为长度为n的序列。检查X的每个子序列是否是Y的子序列,并返回找到的最长的公共子序列。

X2 m个子序列。测试序列是否为Y的子序列需要O(n)时间。因此,朴素的算法将花费O(n2 m )时间。

动态编程

X = 1 ,x 2 ,x 3 ,…,x m >并且Y = 1 ,y 2 ,y 3 ,…,y n >为序列。要计算元素的长度,请使用以下算法。

在此过程中,以行主要顺序计算表C [m,n],并计算另一个表B [m,n]以构造最佳解。

Algorithm: LCS-Length-Table-Formulation (X, Y)
m := length(X) 
n := length(Y) 
for i = 1 to m do 
   C[i, 0] := 0 
for j = 1 to n do 
   C[0, j] := 0 
for i = 1 to m do 
   for j = 1 to n do 
      if xi = yj 
         C[i, j] := C[i - 1, j - 1] + 1 
         B[i, j] := ‘D’ 
      else 
         if C[i -1, j] ≥ C[i, j -1] 
            C[i, j] := C[i - 1, j] + 1 
            B[i, j] := ‘U’ 
         else 
         C[i, j] := C[i, j - 1]
         B[i, j] := ‘L’ 
return C and B
Algorithm: Print-LCS (B, X, i, j)
if i = 0 and j = 0 
   return  
if B[i, j] = ‘D’ 
   Print-LCS(B, X, i-1, j-1) 
   Print(xi) 
else if B[i, j] = ‘U’ 
   Print-LCS(B, X, i-1, j) 
else 
   Print-LCS(B, X, i, j-1) 

该算法将打印XY的最长公共子序列。

分析

要填充表,外部for循环迭代m次,内部for循环迭代n次。因此,算法的复杂度为O(m,n) ,其中mn是两个字符串的长度。

在此示例中,我们有两个字符串X = BACDBY = BDCB以找到最长的公共子序列。

遵循算法LCS-Length-Table-Formulation(如上所述),我们计算了表C(显示在左侧)和表B(显示在右侧)。

在表B中,我们分别使用对角线箭头,左箭头和上箭头而不是’D’,’L’和’U’。生成表B后,LCS由函数LCS-Print确定。结果是BCB。

LCS