LCS的定义
o 最长公共子序列,即LongestCommon Subsequence,LCS。
o 一个序列S任意删除若干个字符得到新序列T,则T叫做S的子序列;
o 两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序列。
n 字符串13455与245576的最长公共子序列为455
n 字符串acdfg与adfc的最长公共子序列为adf
o 注意区别最长公共子串(LongestCommon Substring)
n 最长公共字串要求连续
LCS的意义
o 求两个序列中最长的公共子序列算法,广泛的应用在图形相似处理、媒体流的相似比较、计算生物学方面。生物学家常常利用该算法进行基因序列比对,由此推测序列的结构、功能和演化过程。
o LCS可以描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。另一方面,对一段文字进行修改之后,计算改动前后文字的最长公共子序列,将除此子序列外的部分提取出来,这种方法判断修改的部分,往往十分准确。简而言之,百度知道、百度百科都用得上。
暴力求解:穷举法
o 假定字符串X,Y的长度分别为m,n;
o X的一个子序列即下标序列{1,2, …, m}的严格递增子序列,因此,X共有2m个不同子序列;同理,Y有2n个不同子序列,从而穷举搜索法需要指数时间O(2m.2n);
o 对X的每一个子序列,检查它是否也是Y的子序列,从而确定它是否为X和Y的公共子序列,并且在检查过程中选出最长的公共子序列;
o 显然,不可取。
LCS的记号
o 字符串X,长度为m,从1开始数;
o 字符串Y,长度为n,从1开始数;
o Xi=﹤x1,⋯,xi﹥即X序列的前i个字符(1≤i≤m)(Xi不妨读作“字符串X的i前缀”)
o Yj=﹤y1,⋯,yj﹥即Y序列的前j个字符(1≤j≤n) (字符串Y的j前缀);
o LCS(X, Y) 为字符串X和Y的最长公共子序列,即为Z=﹤z1,⋯,zk﹥。
n 注:不严格的表述。事实上,X和Y的可能存在多个子串,长度相同并且最大,因此,LCS(X,Y)严格的说,是个字符串集合。即:Z∈ LCS(X , Y) .
LCS解法的探索:xm=yn
o 若xm=yn(最后一个字符相同),则:Xm与Yn的最长公共子序列Zk的最后一个字符必定为xm(=yn)。
n zk=xm=yn
n LCS(Xm , Yn) = LCS(Xm-1 , Yn-1) + xm
o 记LCS(Xm,Yn)=W+xm,则W是Xm-1的子序列;同理,W是Yn-1的子序列;因此,W是Xm-1和Yn-1的公共子序列。
n 反证:若W不是Xm-1和Yn-1的最长公共子序列,不妨记
LCS(Xm-1,Yn-1)=W’,且|W’|>|W|;那么,将W换成W’,得到更长的LCS(Xm,Yn)=W’xm,与题设矛盾。
进一步思考的问题
o 方向数组b是完全可以省略的:
n 数组元素c[i,j]的值仅由c[i-1,j-1],c[i-1,j]和c[i,j-1]
三个值之一确定,因此,在计算中,可以临时判断c[i,j]的值是由c[i-1,j-1],c[i-1,j]和c[i,j-1]中哪一个数值元素所确定,代价是Ο(1)时间。
o 若只计算LCS的长度,则空间复杂度为min(m,n)。
n 在计算c[i,j]时,只用到数组c的第i行和第i-1行。因此,只要用2行的数组空间就可以计算出最长公共子序列的长度。