字符串的相似性:如果将一个串转换成为另一个串所需的操作数最少,那么可以说这两个串是相似的。另外一种权衡的方法是,寻换第三个串s3,如果s3都出现在s1和s2中,且出现的顺序相同,但不要求在s1和s2中连续,那么s3的长度越大,就说明相似度越高。
后一种对相似度概念命名为最长公共子序列。
1、最长公共子序列的特征
如果用暴力搜索的方法求解LCS问题,就要穷举X的所有子序列,对每个子序列进行检查,看它是否是Y的子序列,记录找到的最长的子序列。X对应下标人格集合{1,2,3……m}的一个子集,那么X的子序列就有2^m个。
但其实LCS是具有最优子结构的:
令X={x1,x2,x3……xm}, Y={y1,y2,y3……yn}。Z={z1,z2,z3……zk}为X和Y的任意LCS.则有:
(1)如果xm=yn, 则zk = xm = yn,且Zk-1是Xm-1与Yn-1的LCS.
(2)如果xm!=yn,则zk!=xm意味着Zk-1是Xm-1与Y的LCS
(3)如果xm!=yn,则zk!=yn意味着Zk-1是Yn-1与X的LCS
2、递归解
用dp[i][j]表示Xi与Yj的LCS的长度。
dp[i][j] = 0 if i = 0 or j =0
dp[i][j] = dp[i-1][j-1] +1 if xi = yj
dp[i][j] = max(dp[i-1][j], dp[i][j-1]) if x1!=yj
代码如下:
那么对于字符串相似度的前一种解释,延伸出这样一道算法题目:
计算字符串的相似度,定义了一套操作方法,把两个不同的字符串变得相同,具体操作方法:
(1) 修改一个字符;(2) 增加一个字符;(3) 删除一个字符。
如果所进行的操作数越少,相似度就越高,那么这道题目就转换成了,将两个字符串变为相同的字符串,所需的最小操作数。
对于两个字符:A=xabcdae, B=xfdfa。它们的第一个字符是相同的,那么只需要计算A[2……7]和B[2……5]的距离就可。如果第一个字符不同,那么可以进行这样的操作:
(1)删除A串的第一个字符,然后计算A[2->lenA]与B[1->lenB]。
(2)删除B串的第一个字符,然后计算A[1->lenA]与B[2->lebB]。
(3)修改A串的第一个字符为B串的第一个字符,然后计算A[2……lenA]与B[2……lenB]
(4)修改B串的第一个字符为A串的第一个字符,然后计算A[2……lenA]与B[2……lenB]
(5)增加A串的第一个字符到B串的第一个字符前,然后计算A[1……lenA]与B[2……lenB]
(6)增加B串的第一个字符到A串的第一个字符前,然后计算A[2……lenA]与B[1……lenB]
即,经过一步操作后,将A[1->lenA]与B[2->lenB]变为相同的字符串;将A[2->lenA]与B[1->lenB]变为相同的字符串;将A[2->lenA]与B[2->lenB]变为相同的字符串。这样求最小的操作数,就是求这三种情况的最小值。
令dp[i][j]表示A从第i个字符开始,B从第j个字符开始,所需要的操作数。
那么if A[i]!=B[j] , dp[i][j] = min(dp[i+1][j] , dp[i][j+1], dp[i+1][j+1]) +1
else dp[i][j] = dp[i+1][j+1]
部分代码如下: