Levenshtein字符串距离算法介绍
Levenshtein字符串距离算法介绍
文/开发部 Dimmacro
KMP完全匹配算法和 Levenshtein相似度匹配算法是模糊查找匹配字符串中最经典的算法,配合近期技术栏目关于算法的探讨,上期介绍了KMP算法的一些皮毛,收到了同事的一些反馈,本期再接再厉,搜集了一些资料,简单谈谈Levenshtein相似度匹配算法,希望能抛砖引玉。
算法简介:
Levenshtein distance最先是由俄国科学家Vladimir Levenshtein在1965年发明,其原理是两个字符串之间,由一个经过许可的编辑操作转换成另一个所需的最少步骤。其中许可的编辑操作包括将替换一个字符,插入一个字符,删除一个字符。
概述:
如果要把两个不相同的字符串变得相同,可以通过如下操作方法:
1.修改一个字符(如把“a”替换为“b”)。
2.增加一个字符(如把“abdd”变为“aebdd”)。
3.删除一个字符(如把“travelling”变为“traveling”)。
比如,对于“abcdefg”和“abcdef”两个字符串来说,我们认为可以通过增加或者减少一个“g“的方式来达到目的。无论是增加还是减少,都仅需要一次操作。我们把两个不等字符串使之相等的操作次数定义为两个字符串的距离,这也是Levenshtein算法的核心原理。
如果有两个串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]的距离。
很明显,这是一个递归过程。
示例:
递归计算字符串” GUMBO”与” GAMBOL”的距离
1. 步骤1
设置n为字符串s即"GUMBO"的长度。设置m为字符串t即"GAMBOL"的长度。如果n等于0,返回m并退出。如果m等于0,返回n并退出。构造两个向量v0[m+1] 和v1[m+1],串联0..m之间所有的元素并初始化v0 to 0..m。如下图
|
v0 |
v1 |
|
|
|
|
|
|||||||
|
|
G |
U |
M |
B |
O |
|
|||||||
|
0 |
1 |
2 |
3 |
4 |
5 |
|
|||||||
|
G |
1 |
|
|
|
|
|
|||||||
|
A |
2 |
|
|
|
|
|
|||||||
|
M |
3 |
|
|
|
|
|
|||||||
|
B |
4 |
|
|
|
|
|
|||||||
|
O |
5 |
|
|
|
|
|
|||||||
|
L |
6 |
|
|
|
|
|
|||||||
2. 步骤2
检查 s (i from 1 to n) 中的每个字符。
检查 t (j from 1 to m) 中的每个字符
如果 s[i] 等于 t[j],则编辑代价为 0;如s1=t1=G,所以第四行第三列为0
如果 s[i] 不等于 t[j],则编辑代价为1。s1=G,t2=A,所以第五行第三列为1。
如下图i=1;
|
|
v0 |
v1 |
|
|
|
|
|||||||
|
|
G |
U |
M |
B |
O |
|
|||||||
|
0 |
1 |
2 |
3 |
4 |
5 |
|
|||||||
|
G |
1 |
0 |
|
|
|
|
|||||||
|
A |
2 |
1 |
|
|
|
|
|||||||
|
M |
3 |
2 |
|
|
|
|
|||||||
|
B |
4 |
3 |
|
|
|
|
|||||||
|
O |
5 |
4 |
|
|
|
|
|||||||
|
L |
6 |
5 |
|
|
|
|
|||||||
3. 步骤3
当 i = 2,其原理如步骤2,设置单元v1[j]为下面的最小值之一:
a、紧邻该单元上方+1:v1[j-1] + 1
b、紧邻该单元左侧+1:v0[j] + 1
c、该单元对角线上方和左侧+cost:v0[j-1] + cost(cost值为对角线上方即上一个字符比较结果,相等为0,不等为1)
如下图展示
|
|
v0 |
v1 |
|
|
|
|
|||||||
|
|
G |
U |
M |
B |
O |
|
|||||||
|
0 |
1 |
2 |
3 |
4 |
5 |
|
|||||||
|
G |
1 |
0 |
1 |
|
|
|
|||||||
|
A |
2 |
1 |
1 |
|
|
|
|||||||
|
M |
3 |
2 |
2 |
|
|
|
|||||||
|
B |
4 |
3 |
3 |
|
|
|
|||||||
|
O |
5 |
4 |
4 |
|
|
|
|||||||
|
L |
6 |
5 |
5 |
|
|
|
|||||||
4. 步骤4
以此类推,当i=3,4,5,如下图:
|
|
|
|
|
v0 |
v1 |
|
|||||||
|
|
G |
U |
M |
B |
O |
|
|||||||
|
0 |
1 |
2 |
3 |
4 |
5 |
|
|||||||
|
G |
1 |
0 |
1 |
2 |
3 |
4 |
|||||||
|
A |
2 |
1 |
1 |
2 |
3 |
4 |
|||||||
|
M |
3 |
2 |
2 |
1 |
2 |
3 |
|||||||
|
B |
4 |
3 |
3 |
2 |
1 |
2 |
|||||||
|
O |
5 |
4 |
4 |
3 |
2 |
1 |
|||||||
|
L |
6 |
5 |
5 |
4 |
3 |
2 |
|||||||
5. 步骤5
从上面的图可以看出,编辑距离就是矩阵右下角的值,v1[m] == 2。由"GUMBO"变换为"GAMBOL"的过程对于我们来说是很直观的,即通过将"A"替换为"U",并在末尾追加"L"这样子(实际上替换的过程是由移除和插入两个操作组合而成的)。
用途:
· Spell checking(拼写检查)
· Speech recognition(语句识别)
· DNA analysis(DNA分析)
· Plagiarism detection(抄袭检测)