2-最长公共子序列问题(无答案)

更新时间:2023-05-09 14:04:48 阅读: 评论:0

最长公共子序列问题(LCS)(生物信息学中常用算法)
子序列的概念   
X=< x1, x2,, xm>,若有1i1< i2< <ikm,使得
Z=< z1, z2,, zk> = < xi1, xi2,, xik>,则称ZX的子序列,
记为Z<X
e.g. X=<A,B,C,B,D,A,B>,  Z=<B,C,B,A>,  则有Z<X
公共子序列的概念:
XY是两个序列,且Z<XZ<Y
则称ZXY 的公共子序列。
最长公共子序列的概念
Z<XZ<Y,且不存在比Z更长的XY 的公共子序列
则称ZXY 的最长公共子序列,记为ZLCS(X , Y)
最长公共子序列往往不止一个
e.g. X=<A,B,C,B,D,A,B>,  Y=<B,D,C,A,B,A>,
Z=<B,C,B,A>,  Z’=<B,C,A,B>,  Z’’=<B,D,A,B>
均属于LCS(X , Y) ,即X,Y3LCS
如何找出XY一个最长公共子序列?
Brute-force法:列出X的所有长度不超过n(即Y)的子序列,
从长到短逐一进行检查,看其是否为Y的子序列,
直到找到第一个最长公共子序列。
由于X共有2m个子序列,故此方法对较大的m没有实用价值。
是否能使用动态规划法?如何用?
分析:
Xi=x1,…,xi﹥即X序列的前i个字符 (1im)(前缀)
Yj=y1,…,yj﹥即Y序列的前j个字符 (1jn)(前缀)
假定Z=z1,…,zk﹥∈LCS(X , Y)
xm=yn(最后一个字符相同),则不难用反证法证明:
该字符必是XY任一最长公共子序列Z(设长度为k)的
最后一个字符,即有zk = xm = yn 且显然有Zk-1LCS(Xm-1 , Yn-1)
Z的前缀Zk-1Xm-1Yn-1的最长公共子序列。
xmyn,则亦不难用反证法证明:
要么ZLCS(Xm-1, Y),要么ZLCS(X , Yn-1)
由于zkxmzkyn其中至少有一个必成立,因此:
zkxm则有ZLCS(Xm-1 , Y)
zkyn 则有ZLCS(X , Yn-1)   
xm=yn,则问题化归成求Xm-1Yn-1LCS
  LCS(X , Y)的长度等于LCS(Xm-1 , Yn-1)的长度加1
  xmyn 则问题化归成求Xm-1YLCSXYn-1LCS
LCS(X , Y)的长度为:
max{LCS(Xm-1 , Y)的长度, LCS(X , Yn-1)的长度}
LCS(Xm-1 , Y)的长度与LCS(X , Yn-1)的长度
这两个问题不是相互独立的:
∵两者都需要求LCS(Xm-1Yn-1)的长度,
因而具有重叠性
另外两个序列的LCS中包含了两个序列的前缀的LCS
故问题具有最优子结构性质考虑用动态规划法。
引进一个二维数组C,用C[i,j]记录XiYjLCS的长度
  如果我们是自底向上进行递推计算,那么在计算C[i,j]之前,
C[i-1,j-1], C[i-1,j]C[i,j-1]均已计算出来。此时我们
根据X[i]=Y[j]还是X[i]Y[j],就可以计算出C[i,j]
X[i]=Y[j],则执行C[i,j]C[i-1,j-1]+1;若X[i]Y[j],则根据:
C[i-1,j]C[i,j-1]C[i,j]C[i-1,j];否则C[i,j]C[i,j-1]。即有
C[i,j]=
e.g. 如下图:
      0  1  2  3  4  5  6
      yj   B  D  C  A  B  A
0  xi  0  0  0  0  0  0  0
                ↑↖   
1  A  0 0 00  11  1
                      ↑↖ 
2  B  0  1 11 1  2 2
                ↑↖       
3  C  0  1 1  2 22 2
                  ↑↖ 
4  B  0  1 1  2 2  3 3
              ↑↖     
5  D  0  1  22 2  3 3
                ↑↖  ↑↖
6  A  0  1  22  33  4
                  ↑↖ 
7  B  0  1  22  3  4 4
为了构造出LCS,使用一个mn的二维数组b
b[i,j]记录C[i,j]是通过哪一个子问题的值求得的,
以决定搜索的方向:
C[i-1,j]C[i,j-1],则b[i,j]中记入“↑”;
C[i-1,j] < C[i,j-1],则b[i,j]中记入“←”;
算法 LCS_L(X,Y,m,n,C)
for i=0 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 x[i]=y[j] then {C[i,j]C[i-1,j-1]+1
                  b[i,j]←“↖” }
}el if C[i-1,j]C[i,j-1] then {C[i,j]C[i-1,j]
                          b[i,j]←“↑” }
  }el{C[i,j]C[i,j-1]
      b[i,j]←“←” }
算法的时间复杂度显然是(m×n)的。
输出一个LCS(X,Y)的递归算法:
LCS_Output(b,X,i,j)
If i=0 or j=0 then return;
If b[i,j]=“↖”then      /*X[i]=Y[j]*/
  {LCS_Output(b,X,i-1,j-1)
        输出X[i]}
el if b[i,j]=“↑”then  /*C[i-1,j]C[i,j-1]*/
    LCS_Output(b,X,i-1,j)
el if b[i,j]=“←” then  /*C[i-1,j]<C[i,j-1]*/
  LCS_Output(b,X,i,j-1)
e.g. 对上述例子调用LCS_Output(b,X,7,6)
算法分析:
  由于每次调用至少向上或向左(或向上向左同时)移动一步
  故最多调用(m+n)次就会遇到i=0j=0的情况,
  此时开始返回。返回时与递归调用时方向相反,步数相同,
  故算法时间复杂度为(mn)
注意:仅用“↑” ,“←” ,“↖”是搜索不到所有的LCS的;
主要是由于在上述LCS_L算法里,
对于语句if C[i-1] C[i,j-1] then ….
没有区分C[i-1,j]C[i,j-1] C[i-1,j]C[i,j-1]
这两种不同的情况。因此,要找出所有的LCS
当满足X[i]Y[j]C[i-1,j]C[i,j-1]时,要执行b[i,j]←“←↑”,
即记录两个搜索方向,才能够据此找出所有的LCS
为节省空间,数组b亦可不用,直接
根据X[i]=Y[j]还是X[i]Y[j]以及C[i,j-1]C[i-1,j]来找出搜索方向:
X[i]=Y[j]等价于b[i,j]=“↖”,
X[i]Y[j]C[i,j-1] > C[i-1,j] 等价于b[i,j]=“←”,
X[i]Y[j]C[i,j-1] < C[i-1,j] 等价于b[i,j]=“↑”,
X[i]Y[j]C[i,j-1] = C[i-1,j] 等价于b[i,j]=“←↑”,
不用b数组可节省(m×n)的空间,但算法写起来稍烦一些。
执行时间的量级两者相同。
如果只需计算LCS的长度而无需求出具体的LCS

本文发布于:2023-05-09 14:04:48,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/102047.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:序列   算法   方向
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图