求最长公共子序列(LCS)
2016-10-24 22:41
260 查看
本总结是是个人为防止遗忘而作,不得转载和商用。
最长公共子序列不要求连续
最长公共子串不要求连续
如:
字符串13455与245576的最长公共子序列为455,最长子串也是455。
字符串acdfg与adfc的最长公共子序列为adf,没有子串子串。
字符串X,长度为m,从1开始数;
字符串Y,长度为n ,从1开始数;
Xi=﹤x1,⋯,xi﹥:X序列的前i个字符 (1≤i≤m)
Yj=﹤y1,⋯,yj﹥:Y序列的前j个字符 (1≤j≤n)
LCS(X, Y) :字符串X和Y的最长公共子序列,即:
Z=﹤z1,⋯,zk﹥。
注:这是不严格的表述。事实上,X和Y的可能存在多个子串,长度相同并且最大,因此,LCS(X,Y)严格的说,是个字符串集合。即:Z∈ LCS(X , Y) .
这要分情况讨论:
情况1:X的第m个字符xm= Y的第n个字符yn
此时:LCS(Xm,Yn) = LCS(Xm-1, Yn-1) + xm。
如:
对于上面的字符串X和Y:
x3 =y3 =‘C’,则:LCS(BDC,ABC)=LCS(BD,AB)+‘C’
x5 =y4=‘B’,则:LCS(BDCAB,ABCB)=LCS(BDCA,ABC)+‘B’
情况2:X的第m个字符xm≠ Y的第n个字符yn
此时:
要么:LCS(Xm,Yn) = LCS(Xm-1, Yn)
要么:LCS(Xm,Yn) = LCS(Xm, Yn-1)
xm= ym时
LCS(Xm, Yn)= LCS(Xm-1, Yn-1) + xm。
xm≠ yn时
LCS(Xm,Yn) = max(
LCS(Xm-1, Yn),LCS(Xm, Yn) = LCS(Xm, Yn-1) )
使用一个二维数组C[m,n],其中C[i, j] 记录序列Xi和Yj的最长公共子序列的长度。
PS:当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故C[i,j]=0。
因此状态转移方程可以写成:
i = 0或j = 0时
C[i,j] = 0
i > 0, j > 0,且xi = yj时
C[i,j] = C[i-1, j-1] + 1
i > 0, j > 0,且xi ≠ yj时
C[i,j] = max( C[i-1, j], C[i, j-1] )
如上图所示:
X= <A, B, C, B, D, A, B>,Y = <B, D, C, A, B, A>,方格中的数字时该位置的LCS[Xi,Yj]。
首先,第0行第0列都赋值为0,因为上面已经说了:i = 0或j = 0时,C[i, j] = 0
假设现在求LCS[X4,Y3],如箭头所指。
因为此时i=4>0,j=3>0,且x4≠y3,所以:
LCS[X4,Y3] = max(LCS(X3, Y3), LCS(X4, Y2))= max(1, 2) = 2。
接下来的就是遍历完所有的i,j就有了上面的表的内容。
剩下的,想求谁的LCS则直接从表中取就是。
这样做:
刚才是从i=0, j=0遍历到i=7, j=6,那现在就从i=7,j=6往回查找,查找的方式如下:
1,将当前的字母追加至保存用的字符串,然后判断:
如果i或j等于0,反转保存用的字符串并返回;
反之,执行第二步。
2,查看左边和上边的值:
如果xi≠ yj:
如果LCS(Xi-1,Yj) = LCS(Xi, Yj-1):向上走,然后回到第1步
如果LCS(Xi-1,Yj) ≠LCS(Xi, Yj-1):走到值大的位置,然后回到第1步。
如果xi= yj:走到当前位置的左上角,然后回到第1步。
PS:如果在“xi≠ yj 时的如果LCS(Xi-1, Yj) = LCS(Xi, Yj-1)”的情况下选择向左走,则会得到另一个结果,但这也是对的,所以LCS(X, Y)有多个解,当然LCS的长度都一样。
不过,如果仅仅是求LCS的长度而不用求LCS本身时,则不需要保存这个表,因为我们计算第i行时最多只使用第i-1行的数据,用不到i-2行的数据,所以只需要每次保存当前行以供下次计算就好,也就是使用滚动数组的方式。
所以,如果仅仅是求LCS的长度而不用求LCS本身时可以使用用滚动数组:
1, 创建个长度是7的数组,并将其初始化为[0,0,0,0,0,0,0],这是第一行
2, 到第二行时,该行对应的字母是A,然后让A和每一列进行比对:
第一个因为是第一列,所以还强制为0
第二列:因为A != B,所以L22= max(L12, L21)
…
第五列:因为 A = A,所以 L24= L13 + 1
…
就这样递归
这样空间复杂度就是O(m)。
LCS的定义
其实看字面意思就知道LCS是什么了,这里主要是提醒注意区别最长公共子串。最长公共子序列不要求连续
最长公共子串不要求连续
如:
字符串13455与245576的最长公共子序列为455,最长子串也是455。
字符串acdfg与adfc的最长公共子序列为adf,没有子串子串。
题目
求两个字符串的LCS。记号
为了方便说明,这里先做一些记号:字符串X,长度为m,从1开始数;
字符串Y,长度为n ,从1开始数;
Xi=﹤x1,⋯,xi﹥:X序列的前i个字符 (1≤i≤m)
Yj=﹤y1,⋯,yj﹥:Y序列的前j个字符 (1≤j≤n)
LCS(X, Y) :字符串X和Y的最长公共子序列,即:
Z=﹤z1,⋯,zk﹥。
注:这是不严格的表述。事实上,X和Y的可能存在多个子串,长度相同并且最大,因此,LCS(X,Y)严格的说,是个字符串集合。即:Z∈ LCS(X , Y) .
分析
假设我们已经求出了Xm-1和Yn-1的LCS,即,求出了LCS(Xm-1,Yn-1),那如何求LCS(Xm, Yn)呢?这要分情况讨论:
情况1:X的第m个字符xm= Y的第n个字符yn
此时:LCS(Xm,Yn) = LCS(Xm-1, Yn-1) + xm。
如:
对于上面的字符串X和Y:
x3 =y3 =‘C’,则:LCS(BDC,ABC)=LCS(BD,AB)+‘C’
x5 =y4=‘B’,则:LCS(BDCAB,ABCB)=LCS(BDCA,ABC)+‘B’
情况2:X的第m个字符xm≠ Y的第n个字符yn
此时:
要么:LCS(Xm,Yn) = LCS(Xm-1, Yn)
要么:LCS(Xm,Yn) = LCS(Xm, Yn-1)
状态转移方程
根据上面的说明,就可以写出状态转移方程了,如下:xm= ym时
LCS(Xm, Yn)= LCS(Xm-1, Yn-1) + xm。
xm≠ yn时
LCS(Xm,Yn) = max(
LCS(Xm-1, Yn),LCS(Xm, Yn) = LCS(Xm, Yn-1) )
实现
它的实现一般采用如下的方式。使用一个二维数组C[m,n],其中C[i, j] 记录序列Xi和Yj的最长公共子序列的长度。
PS:当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故C[i,j]=0。
因此状态转移方程可以写成:
i = 0或j = 0时
C[i,j] = 0
i > 0, j > 0,且xi = yj时
C[i,j] = C[i-1, j-1] + 1
i > 0, j > 0,且xi ≠ yj时
C[i,j] = max( C[i-1, j], C[i, j-1] )
例子
如上图所示:
X= <A, B, C, B, D, A, B>,Y = <B, D, C, A, B, A>,方格中的数字时该位置的LCS[Xi,Yj]。
首先,第0行第0列都赋值为0,因为上面已经说了:i = 0或j = 0时,C[i, j] = 0
假设现在求LCS[X4,Y3],如箭头所指。
因为此时i=4>0,j=3>0,且x4≠y3,所以:
LCS[X4,Y3] = max(LCS(X3, Y3), LCS(X4, Y2))= max(1, 2) = 2。
接下来的就是遍历完所有的i,j就有了上面的表的内容。
剩下的,想求谁的LCS则直接从表中取就是。
如何求LCS的内容
上面时求LCS的长度,那如果相求LCS的内容呢?这样做:
刚才是从i=0, j=0遍历到i=7, j=6,那现在就从i=7,j=6往回查找,查找的方式如下:
1,将当前的字母追加至保存用的字符串,然后判断:
如果i或j等于0,反转保存用的字符串并返回;
反之,执行第二步。
2,查看左边和上边的值:
如果xi≠ yj:
如果LCS(Xi-1,Yj) = LCS(Xi, Yj-1):向上走,然后回到第1步
如果LCS(Xi-1,Yj) ≠LCS(Xi, Yj-1):走到值大的位置,然后回到第1步。
如果xi= yj:走到当前位置的左上角,然后回到第1步。
PS:如果在“xi≠ yj 时的如果LCS(Xi-1, Yj) = LCS(Xi, Yj-1)”的情况下选择向左走,则会得到另一个结果,但这也是对的,所以LCS(X, Y)有多个解,当然LCS的长度都一样。
时间复杂度
上面是打了一个m*n的表,所以时间复杂度和空间复杂度是O(m*n)。不过,如果仅仅是求LCS的长度而不用求LCS本身时,则不需要保存这个表,因为我们计算第i行时最多只使用第i-1行的数据,用不到i-2行的数据,所以只需要每次保存当前行以供下次计算就好,也就是使用滚动数组的方式。
所以,如果仅仅是求LCS的长度而不用求LCS本身时可以使用用滚动数组:
1, 创建个长度是7的数组,并将其初始化为[0,0,0,0,0,0,0],这是第一行
2, 到第二行时,该行对应的字母是A,然后让A和每一列进行比对:
第一个因为是第一列,所以还强制为0
第二列:因为A != B,所以L22= max(L12, L21)
…
第五列:因为 A = A,所以 L24= L13 + 1
…
就这样递归
这样空间复杂度就是O(m)。
相关文章推荐
- 算法导论-----最长公共子序列LCS(动态规划)
- 转【算法之动态规划(三)】动态规划算法之:最长公共子序列 & 最长公共子串(LCS)&字符串相似度算法
- BZOJ2423 [HAOI2010]最长公共子序列 (LCS)
- 动态规划问题--最长公共子序列(LCS)问题--删除一些字符使得剩下的是一个回文子串
- 最长公共子序列(LCS)的C++实现
- 最长公共子序列(LCS)模板
- LCS:最长公共子序列
- 三、动态规划算法解最长公共子序列LCS问题(2011.12.13重写)
- 最长公共子序列(LCS)
- HDU - 1159 Common Subsequence(LCS最长公共子序列)
- 最长公共子序列LCS简介
- LCS最长公共子序列
- Algorithm3——最长公共子序列(LCS)
- 最长公共子序列lcs
- 算法系列之六:最长公共子序列(LCS)问题(连续子序列)的三种解法
- 最长公共子序列(可打印LCS)
- 算法系列之五:最长公共子序列(LCS)问题(非连续子序列)的两种解法
- POJ 2250 Compromise(文章的最长公共子序列LCS)
- 最长上升子序列(LIS)与最长公共子序列(LCS)
- 最长公共子序列(LCS)