[版权声明]:本文章由danvid发布于http://danvid.cnblogs.com/,如需转载或部分使用请注明出处
最近看到一些动态规划的东西讲到莱文斯坦距离(编辑距离)的计算,发现很多都讲的不是很清楚,比较难理解,自己思考过后重新给大家讲解一下;
维基百科解析:莱文斯坦距离,又称Levenshtein距离,是编辑距离的一种。指两个字串之间,由一个转成另一个所需的最少编辑操作次数。允许的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。例如将kitten转成sitting:
sitten (k→s)
sittin (e→i)
sitting(→g)
俄罗斯科学家弗拉基米尔·莱文斯坦在1965年提出这个概念。
意思很好明白,这东西主要用在文本相似度匹配上就是通过这个最小距离来判断两个文本相似度情况,ES临近搜索(match_phrase)的打分也是基于这个编辑距离进行的,编辑距离越小则表示文本越接近,那么现在就是要求出最小的编辑距离。
先给出计算公式再解析原理:
假如两个字符串分别是String A="abc"和String B="abbf"做成一个二维数组 i代表B的序号[行],j代表A的序号[列],i或者j等于0的时候代表大家都是空字符串
0 | a | b | c | |
0 | ||||
a | ||||
b | ||||
b | ||||
f |
1.如果i=0或者j=0,edit(i,j)=j或者i
2.如果i&&j>=1 则edit(i,j)=min{edit(i-1,j)+1,edit(i,j-1)+1,edit(i-1,j-1)+x} 如果B[i]=A[j]相等,则x=0,否则x=1;
其实思想就是基于上一个状态的最小距离,推出下一个的最小距离,对于两个数据A,B来说,如何找出他们的上一个状态呢,其实穷举一下就可以了假设当前状态大家都是一个字符A="a",B="a",那么他们上一个状态有以下3种情况,A="",B="a"|A="a",B=""|A="",B=""对应其实就是 edit(i-1,j)|edit(i,j-1)|edit(i-1,j-1),在表结构对应的位置就是当前位置的上|左|右上。而对于edit(i-1,j)|edit(i,j-1)这两种情况无论怎么样,他们要转换到当前状态至少都要加1的编辑距离,例如A="",B="a"变到A="a",B="a" A要增加1个编辑距离,而对于edit(i-1,j-1)如果edit(i,j)中i对应的字符等于j其实是不用增加编辑距离的,例如A="",B=""到A="a",B="a",时原本的编辑距离是0,现在还是0,但如果i,j对应的字符不相等,例如A="ab",B="ab"到A="abb",B="abc",其实是从原来的编辑距离是0,变成了1,所以最小编辑距离应该是上一个编辑距离edit(i-1,j-1)+1 ,理解这个推理就理解情况2了,理解情况2,情况1一看就知道这里不解析了,然后就可以按这个思想推出下面的表
条件1时:
0 | a | b | c | |
0 | 0 | 1 | 2 | 3 |
a | 1 | |||
b | 2 | |||
b | 3 | |||
f | 4 |
递推执行条件2:
0 | a | b | c | |
0 | 0 | 1 | 2 | 3 |
a | 1 | 0 | ||
b | 2 | 1 | ||
b | 3 | 2 | ||
f | 4 | 3 |
0 | a | b | c | |
0 | 0 | 1 | 2 | 3 |
a | 1 | 0 | 1 | |
b | 2 | 1 | 0 | |
b | 3 | 2 | 1 | |
f | 4 | 3 | 2 |
0 | a | b | c | |
0 | 0 | 1 | 2 | 3 |
a | 1 | 0 | 1 | 2 |
b | 2 | 1 | 0 | 1 |
b | 3 | 2 | 1 | 1 |
f | 4 | 3 | 2 | 2 |
看到这里如果还觉得不够清楚的话,自己对着上面的表格自己尝试一个一个计算一下最小编辑距离,随着字符的增加,你一定会发现跟上一个状态的字符编辑距离是有关系的,这里再说一点,为什么我们都是只做加1而不是加2加3,是因为假如上一个字符对的编辑距离是x,这个字符对任意一个字符的增加最多只会增加1个编辑距离,如果还理解不了还是自己对着表个去一个一个字符往上加对比就会发现规律。
以上就是我的通俗讲解,至于代码实现我觉得大家理解了之后应该都会写,就不在这增加篇幅了,网上也很多,大家可以找找。