计算字符串距离

来源:互联网 发布:淘宝店铺开通了 编辑:程序博客网 时间:2024/06/05 14:04

编辑距离,又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。Levenshtein距离可以通过下面这个状态方程求解:


这个式子还是比较好理解的:当字符串a为空,那么两个字符串之间的距离就是另一个字符串b的长度,因为可以通过删除strlen(b)个字符后编程空字符。其它三个方程类似。

在《编程之美》中使用了递归的方法,就是将上述方程原封不动的表示了出来,代码如下:

<span style="font-size:14px;">// 递归法计算字符串距离(Levenshtein距离)int StringDistance(char *str1, char *str2){// str1、str2不能为NULLif (*str1 == '\0'){if (*str2 == '\0')return 0;elsereturn strlen(str2);}if (*str2 == '\0'){if (*str1 == '\0')return 0;elsereturn strlen(str1);}if (*str1 == *str2)return StringDistance(str1 + 1, str2 + 1);else{int d1 = StringDistance(str1 + 1, str2);// str2增加一个字符int d2 = StringDistance(str1, str2 + 1);// str2删除一个字符int d3 = StringDistance(str1 + 1, str2 + 1);// str2修改一个字符return min(min(d1, d2), d3) + 1;}}</span>

但这样的代码是存在重复计算的,改进后的动态规划方法使用一个二维数组保存中间变量,代码如下:

<span style="font-size:14px;">// 动态规划计算字符串距离(Levenshtein距离)int StringDistance_DP(char *str1, char *str2){int len1 = strlen(str1);int len2 = strlen(str2);// D[i][j]表示str1[0]~str1[i-1]和str2[0]~str2[j-1]之间的字符串距离int **D = new int*[len1 + 1];for (int i = 0; i <= len1; i++)D[i] = new int[len2 + 1];// str2长度为0,距离为str1的长度for (int i = 0; i <= len1; i++)D[i][0] = i;// str1长度为0,距离为str2的长度for (int j = 0; j <= len2; j++)D[0][j] = j;for (int i = 1; i <= len1; i++){for (int j = 1; j <= len2; j++){// 若str1[i-1]和str2[j-1]相等,则距离不增加if (str1[i - 1] == str2[j - 1])D[i][j] = D[i - 1][j - 1];else// D[i][j - 1] + 1:删除str2[j-1],长度+1// D[i - 1][j] + 1:删除str1[i-1],长度+1// 若str1[i-1]和str2[j-1]不相等,则执行替换操作,距离+1D[i][j] = min(min(D[i][j - 1] + 1, D[i - 1][j] + 1), D[i - 1][j - 1] + 1);}}for (int i = 0; i <= len1; i++){for (int j = 0; j <= len2; j++)cout << D[i][j] << ' ';cout << endl;}int res = D[len1][len2];for (int i = 0; i <= len1; i++)delete[] D[i];delete[] D;return res;}</span>

当str1 = "Saturday",str2 = "Sunday"时,这样便形成如下矩阵:



程序运行结果和上面的矩阵相同,程序无误,右下角的3就是两个字符串的Levenshtein距离,这又是一个使用动态规划解题的典型例子。



参考:

维基百科:http://en.wikipedia.org/wiki/Levenshtein_distance

《编程之美》

0 0