文本相似度算法之编辑距离算法
Posted raintungli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文本相似度算法之编辑距离算法相关的知识,希望对你有一定的参考价值。
定义
编辑距离又称Leveinshtein距离,是由俄罗斯科学家Vladimir Levenshtein在1965年提出。
以字符串为例,字符串a和字符串b的编辑距离是将a转换成b的最小操作次数,这里的操作包括三种:
插入一个字符
删除一个字符
替换一个字符
举个例子,
计算learning和meaning的编辑距离,需要下列步骤
- learning -> mearning 将k替换成s
- mearning -> meaning 将r删除
至少要做2次操作,编辑距离为2
公式
用
e
d
a
,
b
(
i
,
j
)
ed_a,b(i,j)
eda,b(i,j)来表示a,b字符串的编辑距离,其中i代表a的长度,j代表b的长度
e
d
a
,
b
(
i
,
j
)
=
m
i
n
(
i
,
j
)
=
0
max
(
i
,
j
)
a
i
=
b
j
e
d
a
,
b
(
i
−
1
,
j
−
1
)
a
i
<
>
b
j
min
(
e
d
a
,
b
(
i
−
1
,
j
−
1
)
+
1
,
e
d
a
,
b
(
i
−
1
,
j
)
+
1
,
e
d
a
,
b
(
i
,
j
−
1
)
+
1
)
ed_a,b(i,j)=\\left\\ \\beginaligned min(i,j) =0 && \\max(i,j) \\\\ a_i = b_j && ed_a,b(i-1,j-1)\\\\ a_i <> b_j && \\min(ed_a,b(i-1,j-1)+1,ed_a,b(i-1,j)+1,ed_a,b(i,j-1)+1) \\endaligned \\right.
eda,b(i,j)=⎩⎪⎨⎪⎧min(i,j)=0ai=bjai<>bjmax(i,j)eda,b(i−1,j−1)min(eda,b(i−1,j−1)+1,eda,b(i−1,j)+1,eda,b(i,j−1)+1)
e
d
a
,
b
(
i
,
j
)
ed_a,b(i,j)
eda,b(i,j)的值描述如下:
- min(i,j)=0 代表有一个字符串为空,编辑距离就是另一个非空字符串的长度
- 当字符 a i a_i ai值等于 b j b_j bj的时候,编辑距离就是a,b字符串上一个字符的编辑距离 e d a , b ( i − 1 , j − 1 ) ed_a,b(i-1,j-1) eda,b(i−1,j−1)
- 当
a
i
a_i
ai值不等于
b
j
b_j
bj的时候,编辑距离如下三种情况的最小值
- e d a , b ( i − 1 , j ) + 1 ed_a,b(i-1,j)+1 eda,b(i−1,j)+1 删除 a i a_i ai
- e d a , b ( i , j − 1 ) + 1 ed_a,b(i,j-1)+1 eda,b(i,j−1)+1 插入 b j b_j bj
- e d a , b ( i − 1 , j − 1 ) + 1 ed_a,b(i-1,j-1)+1 eda,b(i−1,j−1)+1 替换 b j b_j bj
矩阵
在前面的公式中,我们可以很明显的感觉到可以用一个二维矩阵来表达该距离
我们用learn(a)和mean(b)比较简单的单词用矩阵来表达:
- 初始化:在矩阵的第1行的时候,表示b的长度为0,根据第一个规则,当b长度为0的时候,a的编辑距离就是a字符串的长度,也就是mean的1,2,3,4,反之第一列也是如此
0 | m | e | a | n | |
---|---|---|---|---|---|
0 | 0 | 1 | 2 | 3 | 4 |
l | 1 | ||||
e | 2 | ||||
a | 3 | ||||
r | 4 | ||||
n | 5 |
0 | m | e | a | n | |
---|---|---|---|---|---|
0 | 0 | 1 | 2 | 3 | 4 |
l | 1 | m!=l 所以取min(0+1,1+1,1+1)=1 | |||
e | 2 | ||||
a | 3 | ||||
r | 4 | ||||
n | 5 |
0 | m | e | a | n | |
---|---|---|---|---|---|
0 | 0 | 1 | 2 | 3 | 4 |
l | 1 | 1 | e!=l 所以取min(1+1,2+1,1+1)=2 | ||
e | 2 | ||||
a | 3 | ||||
r | 4 | ||||
n | 5 |
如此持续迭代,直至推导最终结果
0 | m | e | a | n | |
---|---|---|---|---|---|
0 | 0 | 1 | 2 | 3 | 4 |
l | 1 | 1 | 2 | 3 | 4 |
e | 2 | 2 | 1 | 2 | 3 |
a | 3 | 3 | 2 | 1 | 2 |
r | 4 | 4 | 3 | 2 | 2 |
n | 5 | 5 | 4 | 3 | 2 |
最后的编辑距离就是2
算法优化
当i<j的时候,最小的时间复杂度O ( i 2 ) (i^2) (i2),最小空间复杂度是O ( 2 ∗ i ) (2*i) (2∗i)
为何复杂度不是O
(
i
∗
j
)
(i*j)
(i∗j)?
当我们只是计算编辑距离的时候,只是求矩阵的最后一个值。当字符串的长度i<j的时候,我们并不需要继续计算在区间i到j的距离,因为在这种场景下只是插入字符到尾部,依据定义,只要将(j-i-1)差值直接加上就可,无需在继续计算
为何最小空间复杂度是O
(
2
∗
i
)
(2*i)
(2∗i)
在我们计算的时候,发现只是需要2行也就是当前行和前一行的状态,所以没必要保存完整的矩阵,而只需要保存2行矩阵
优化后的代码如下:
public static int editDistance(String left, String right)
if(left.length() > right.length())
String tmp = left;
left = right;
right = tmp;
int x,y,gap = 0;
if(right.length() == left.length())
x = left.length();
y = x;
else
x = left.length()+1;
y = left.length();
gap = right.length() - left.length() -1;
int[] pre = new int[ y + 1];
int[] cur = new int[ y + 1];
for (int i = 0; i < pre.length; i++)
pre[i] = i;
for (int i = 1; i <= x; i++)
cur[0] = i;
for (int j = 1; j <= y; j++)
if (right.charAt(i - 1) == left.charAt(j - 1))
cur[j] = pre[j - 1];
else
cur[j] = Math.min(cur[j - 1], Math.min(pre[j], pre[j - 1])) + 1;
int[] tmp = pre;
pre = cur;
cur = tmp;
return pre[pre.length - 1]+gap;
以上是关于文本相似度算法之编辑距离算法的主要内容,如果未能解决你的问题,请参考以下文章