前几天更新了关于TFIDF的,写到了LCS部分本狗也是当了我最讨厌的断更狗,决定拖延一段来写关于LCS的部分。
LCS(最长公共子序列):一个序列S任意删除若干字符达到的新序列T,则T叫做S的子序列,两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序列。
目的:从字面的角度来衡量字面相似度的方法之一。
那么什么是LCS呢?它和我们之前接触的最长公共子串不一样,老规矩,举一个例子。
- eg:字符串12455与245576的最长公共子序列为2455
- 字符串acdfg与adfc的最长公共子序列为adf
谨记:公共子串要求是连续的,而最长公共子序列不要求。
那么怎样求解呢?最简单的方法就是暴力穷举法。
假定字符串X,Y的长度分别为m,n;
X的一个子序列即下标序列{1,2,……,m}严格递增子序列,因此,X共有2m个 不同子序列;同理,Y有2n个不同子序列;
穷举搜索法时间复杂度O(2m ∗ 2n);
但是这种方法复杂度太高,并不可取。
我们应该采用动态规划法来求解。
字符串X,长度为m,从1开始数;
字符串Y,长度为n,从1开始数;
Xi=<x1,……,xi>即X序列的前i个字符(1<=i<=m)(Xi计作“字符串X的i前缀”)
Yi=<y1,……,yi>即Y序列的前j个字符(1<=j<=n)(Yj计作“字符串Y的j前缀”)
LCS(X,Y)为字符串X和Y的最长公共子序列,即为Z=<z1,……,zk>
如果xm = yn(最后一个字符相同),则:X?与Yn的最长公共子序列Zk的最后一个字符必定为 xm(= yn) • ?? = xm = yn• LCS(X?, Yn)=LCS(X?−1, Yn−1)+xm
用一个例子来说名一下
- eg:如果有Xm=Ym
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
x | B | D | C | A | B | A | |
y | A | B | C | B | D | A | B |
对于上面的字符串来说
X3=Y3='C',则有LCS(BDC,ABC)=LCS(BD,AB)+C
X5=X4='B',则有LCS (BDCAB,ABCB) = LCS (BDCA,ABC)+B
- 如果xm ≠ yn,则LCS(X?, Yn)=LCS(X?−1, Yn),或者LCS(X?, Yn)=LCS(X?, Yn−1)
即LCS(X?, Yn)=max{LCS(X?−1, Yn), LCS(X?, Yn−1)}
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
x | B | D | C | A | B | A | |
y | A | B | C | B | D | A | B |
对于上面的字符串X和Y:
x2 ≠ y2则有:LCS(BD, AB)=max{LCS(BD, A), LCS(B, AB)}
x4 ≠ y5则有: LCS(BDCA, ABCBD)=max{LCS(BDCA, ABCB), LCS(BDC, ABCBD)}
由此可推出公式
- 想要用代码的方式完成,首先完成它的数据结构
使用二维数组C[m,n]
C[i,j]记录序列Xi和Yj的最长公共子序列的长度 – 当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故C[i,j]=0
举一个例子
eg:
X=<A,B,C,B,D,A,B>
Y=<B,D,C,A,B,A>
运用动态规划的方法求出最长公共子序列。
i A B C B D A B j 0 0 0 0 0 0 0 0 B 0 0 1 1 1 1 1 1 D 0 0 1 1 1 2 2 2 C 0 0 1 2 2 2 2 2 A 0 1 1 2 2 2 3 3 B 0 1 2 2 3 3 3 4 A 0 1 2 2 3 3 4 4 从第一行看,由公式可知,当i或者j任意一个为0则为0,可得到表格中第二行第二列都是0.
第三列和A和第三行B不相等,由公式可知,为行-1,列-1取最大值得到0
看第四列B和第三行B,相等,由公式,行列同时-1,在这个值上+1,
根据此规律,可以得到整个表.
观察表,得出共有三个最长公共子序列的结论(右下脚三个最大值4,可知长度为4,共有三个)
结果:BCBA,BCAB,BDAB
score = 4
len(x) = 7
len(y) = 6
sim(x,y) = 4 *2 / (6+7) = 0.615
为什么要乘2呢?eg:
两个句子,长度相等,字符相同,最终的值应该为1 要是不乘2则为:
x=4 y=4 c=4
4/(4+4) = 0.5因此需要乘2