计算字符串的相似度
题目:
对于不同的字符串,我们希望能够有办法判断其相似程度。我们定义了一套操作方法来把两个不相同的字符串变得相同,具体的操作方法为:
1. 修改一个字符(如把“a”替换为“b”)
2. 增加一个字符(如把“abdd”变为“aebdd”)
3. 删除一个字符(如把“travelling”变为“traveling”)
比如,对于“abcdefg”和“abcdef”两个字符串来说,我们认为可以通过增加/减少一个“g”的方式来达到目的。上面的两种方案,都仅需要一次操作。把这个操作所需要的次数定义为两个字符串的距离,而相似度等于“距离+1”的倒数。也就是说,“abecdefg”和“abcedfg”.
的距离为1,相似度为1/2 = 0.5;
给定任意两个字符串,你是否能写出一个算法来计算他们的相似度呢?
分析与解法
不难看出,两个字符串的距离肯定不超过它们的的长度之和。
考虑如何才能把这个问题转换成规模较小的同样的问题。如果有两个串A=xabcdae和B=xfdfa,他们的第一个字符是相同的,只要计算A[2,…,7]=abcdae和B[]2,…,5=fdfa的距离就可以了。但是,如果两个串的第一个字符不相同,那么可以进行如下的操作(lenA和lenB分别是A串和B串的长度)。
1. 删除A串的第一个字符,然后计算A[2,…,lenA]和B[1,…,lenB]的距离
2. 删除B串的第一个字符,然后计算A[1,…,lenA]和B[2,…,lenB]的距离
3. 修改A串的第一个字符为B串的第一个字符,然后计算A[2,…,lenA]和B[2,…,lenB]的距离
4. 修改B串的第一个字符为A串的第一个字符,然后计算A[2,…,lenA]和B[2,…,lenB]的距离
5. 增加B串的第一个字符到A串的第一个字符之前,然后计算A[1,…,lenA]和B[2,…,lenB]的距离(设想原串不变,继续比较第一个字符之后的串)
6. 增加A串的第一个字符到B串的第一个字符前,然后计算A[2,…,lenA]和B[1,…,lenB]的距离
在这个题目中,我们并不在乎两个字符串变得相等之后的字符串是怎样的。所以,可以将上面6个操作合并为:
1. 一步操作后,再将A[2,…,lenA]和B[1,…,lenB]变成相同的字符串
2. 一步操作后,再将A[1,…,lenA]和B[2,…,lenB]变成相同的字符串
3. 一步操作后,再将A[2,…,lenA]和B[2,…,lenB]变成相同的字符串
这样,很快就可以完成一个递归程序
代码清单:
//略,下给出优化的代码
上述程序有些数据被重复计算了,可以使用数组存储子问题的解。
//使用数组的代码
int checkPoint[20][20] = {0};//使用数组来存储子问题是否已经计算 int minValue(int t1,int t2,int t3){ int temp = t1 < t2 ? t1 : t2; return temp < t3 ? temp : t3; } int CalculateStringDistance(string strA,int pABegin,int pAEnd,string strB,int pBBegin,int pBEnd){ if(pABegin > pAEnd){//A串到末尾了,两串比较完成了 if(pBBegin > pBEnd)//B串也到末尾了,则说明两串距离为0 return 0; else return pBEnd - pBBegin + 1; } if(pBBegin > pBEnd){ if(pABegin > pAEnd) return 0; else return pAEnd - pABegin + 1; } if(strA[pABegin] == strB[pBBegin]){ return CalculateStringDistance(strA,pABegin + 1,pAEnd,strB,pBBegin + 1,pBEnd); }else{ int t1 = 0,t2 = 0, t3 = 0; if(checkPoint[pABegin + 1][pBBegin] == 0){ checkPoint[pABegin + 1][pBBegin] = t1 = CalculateStringDistance(strA,pABegin + 1,pAEnd,strB,pBBegin,pBEnd); }else{ t1 = checkPoint[pABegin + 1][pBBegin]; } if(checkPoint[pABegin][pBBegin + 1] == 0){ checkPoint[pABegin][pBBegin + 1] = t2 = CalculateStringDistance(strA,pABegin,pAEnd,strB,pBBegin + 1,pBEnd); }else{ t2 = checkPoint[pABegin][pBBegin + 1]; } if(checkPoint[pABegin + 1][pBBegin + 1] == 0){ checkPoint[pABegin + 1][pBBegin + 1] = t3 = CalculateStringDistance(strA,pABegin + 1,pAEnd,strB,pBBegin + 1,pBEnd); }else{ t3 = checkPoint[pABegin + 1][pBBegin + 1]; } return minValue(t1,t2,t3) + 1; } }