字符串的编辑距离即Levenshtein距离,指在两个字符串之间由其中一个字符串通过插入、删除、替换的编辑操作转换为另一个字符串的最小代价,可以当作距离一样来衡量两个字符串之间的相似程度,距离越大则相似程度越低,距离越小则相似程度越高。比如求takers和lakers之间的编辑距离,设插入和删除的代价是1,替换等于删除并插入,故替换的代价是2,takers经过删除t和插入l两步操作可以转换为lakers,那么它们之间的编辑距离就是2。在使用编辑距离时,编辑操作的代价函数可以根据实际情况来进行调整。
求解编辑距离的过程,我们可以逐个字符考虑,假设现在有两个字符串string1[w1,w2....wn]和string2[c1,c2...cm],w和c分别为string1和string2的字符。
先考虑第一个字符,
若w1==c1,即两个字符串第一个字符串相等,不需要经过任何编辑操作,编辑距离为0,则我们只需考虑string1[2:n]和string2[2:m]这两个子字符串之间的编辑距离。
若w1!=c1,则要考虑string1和string2需要什么编辑操作来使得w1=c1:
1.删除string1的第一个字符w1,接着继续计算string1[2:n]和string2[1:m]的编辑距离即可。
2.将string第一个字符替换为c1,两个字符串首字符相等,则继续计算string1[2,n]和string2[2,m]即可。
......
考虑string1的第i个字符串和string2的第j个字符串时也是用同样的思想,采用动态规划逐步求解最优值。
下面是编辑距离的计算方法,对于长度为n的string1和长度为m的string2,建立一个(n+2)*(m+2)的表格edit来记录编辑距离。
edit[i][j]表示string1[0:i]和string2[0:j]的编辑距离,当i=0时,代表string1为空字符串的情况,此时将string1转换为string2就需要将string2的j个字符串插入到string1中,即编辑距离为j,反之当j=0时也是同一种情况。
当i>0,j>0时,可以考虑通过插入删除和替换哪种操作可以使得string1第i个字符和string第j个字符相等,经过操作之后,当前的编辑距离就是刚刚操作的代价加上子字符串的编辑距离,如此计算,矩阵右下角就是最终两个完整字符串的编辑距离。
表格的填充规则如下:
实例:
计算cafe和coffee的编辑距离:
首先打好表格:
null | c | o | f | f | e | e | |
null | |||||||
c | |||||||
a | |||||||
f | |||||||
e |
填充第一行第一列
null | c | o | f | f | e | e | |
null | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
c | 1 | ||||||
a | 2 | ||||||
f | 3 | ||||||
e | 4 |
-
如果最上方的字符等于最左方的字符,则为左上方的数字。否则为左上方的数字+1。(对于3,3来说为0)
-
左方数字+1(对于3,3格来说为2)
-
上方数字+1(对于3,3格来说为2)
null | c | o | f | f | e | e | |
null | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
c | 1 | 0 | |||||
a | 2 | ||||||
f | 3 | ||||||
e | 4 |
-
如果最上方的字符等于最左方的字符,则为左上方的数字。否则为左上方的数字+1。(对于3,4来说为2)
-
左方数字+1(对于3,4格来说为1)
-
上方数字+1(对于3,4格来说为3)
null | c | o | f | f | e | e | |
null | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
c | 1 | 0 | 1 | ||||
a | 2 | ||||||
f | 3 | ||||||
e | 4 |
按此规则递推出整个表:
null | c | o | f | f | e | e | |
null | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
c | 1 | 0 | 1 | 2 | 3 | 4 | 5 |
a | 2 | 1 | 1 | 2 | 3 | 4 | 5 |
f | 3 | 2 | 2 | 1 | 2 | 3 | 4 |
e | 4 | 3 | 3 | 2 | 2 | 2 | 3 |