编辑距离
对于字符串的操作一共有三个,分别是:添加字符,删除字符,替换字符
如果我们需要把现有的字符串转换为目标字符,就需要使用以上三种操作,当我们以最少的操作将转换完成,其使用的操作步数就是两个字符串之间的编辑距离
算法图解
对于字符串a[n] = a1a2a3…an和字符串b[m] = b1b2b3…bm,来求这两个字符串的编辑距离
首先建立一个(n+1)(m+1)的二维矩阵C,先初始化C,对于C[0,i] = i,C[i,0] = i,然后我们就还剩下nm个单元未进行操作,接下来就是按照下图进行操作:
这就是LevenshteinDistance的运算法则,其中
的含义是当ai = bj时该值等于0,当ai != bj时该值等于1
该图翻译一下就是:
对于矩阵中任意的C[i,j]
if i = 0 且 j = 0 ,则C[0,0] = 0
if i = 0,则C[0,j] = j
if j = 0,则C[i,0] = i
if i ≥ 1 且 j ≥ 1 ,C[i,j] == min{ C[i-1,j] + 1, C[i,j-1] + 1, C[i-1,j-1] + f(i, j) }
当第一个字符串的第i个字符不等于第二个字符串的第j个字符时,f(i, j) = 1;否则,f(i, j) = 0。
当我们以以上方法求出两个字符串构成的矩阵时,其编辑距离为C[n,m]
算法原理
其实LevenshteinDistance的操作有点类似于动态规划,就像汉罗塔问题一样,我们需要用最少的操作去将字符串a[n]转换为b[m],假设这最少需要k次操作,那么我们就需要用k-1次操作将
1) a[1…n] 转换为 b[1…m-1] (第k次操作添加bm)
2) a[1…n-1]转换为b[1…m] (第k次操作删除an)
3) a[1…n-1] 转换为 b [1…m-1] (第k次操作替换an为bm)
以上三种情况就是C[n,m]对应的C[n-1,m],C[n,m-1],C[n-1,m-1]三个单元,对于当ai = bj时f(i,j) = 0,实际就第三种情况,当ai = bj,我们就不用替换了,在这三种情况中我们当然选取操作数最少的赋值给C[n,m]
具体操作
如图,对于troop和loop建立6*5的矩阵存储数据,然后按LevenshteinDistance方法进行操作
所以troop与loop的编辑距离只有2
代码实现
int LevenshteinDistance(string s1,string s2)
{
int i,j;
int m = s1.length();
int n = s2.length();
int a[m+1][n+1];
for(i = 0;i < m + 1; i ++)
a[i][0] = i;
for(i = 0;i < n + 1; i ++)
a[0][i] = i;
for(i = 1;i < m + 1; i ++)
for(j = 1;j < n + 1; j ++)
{
if(s2[j-1] == s1[i-1])
a[i][j] = Min(a[i][j - 1] + 1,a[i - 1][j] + 1,a[i - 1][j - 1]) ;
else
a[i][j] = Min(a[i][j - 1] + 1,a[i - 1][j] + 1,a[i - 1][j - 1] + 1);
}
return a[m][n];
}
应用范围
LevenshteinDistance编辑距离可以运用输入法,对于输入错误,或者上下文不通顺的情况,可以用该算法去寻找编辑距离最近的以及使用最频繁的输入,然后对用户进行提示