您的位置:首页 > 其它

计算字符串相似度算法——Levenshtein

2016-02-05 17:33 375 查看


计算字符串相似度算法——Levenshtein

博客分类:

我喜欢的算法

levenshtein相似度编辑距离算法实现

0.这个算法实现起来很简单

1.百度百科介绍:

Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数。

许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。

编辑距离的算法是首先由俄国科学家Levenshtein提出的,故又叫Levenshtein Distance。

2.用途

模糊查询

3.实现过程


a.首先是有两个字符串,这里写一个简单的 abc和abe


b.将字符串想象成下面的结构。

A处 是一个标记,为了方便讲解,不是这个表的内容。

abcabc
abe0123
a1A处
b2
e3


c.来计算A处 出得值

它的值取决于:左边的1、上边的1、左上角的0.

按照Levenshtein distance的意思:

上面的值和左面的值都要求加1,这样得到1+1=2。

A处 由于是两个a相同,左上角的值加0.这样得到0+0=0。

这是后有三个值,左边的计算后为2,上边的计算后为2,左上角的计算为0,所以A处 取他们里面最小的0.


d.于是表成为下面的样子

abcabc
abe0123
a10
b2B处
e3
在B处 会同样得到三个值,左边计算后为3,上边计算后为1,在B处 由于对应的字符为a、b,不相等,所以左上角应该在当前值的基础上加1,这样得到1+1=2,在(3,1,2)中选出最小的为B处的值。


e.于是表就更新了

abcabc
abe0123
a10
b21
e3C处
C处 计算后:上面的值为2,左边的值为4,左上角的:a和e不相同,所以加1,即2+1,左上角的为3。

在(2,4,3)中取最小的为C处 的值。


f.于是依次推得到

abc
0123
a1A处 0D处 1G处 2
b2B处 1E处 0H处 1
e3C处 2F处 1I处 1
I处: 表示abc 和abe 有1个需要编辑的操作。这个是需要计算出来的。

同时,也获得一些额外的信息。

A处: 表示a 和a 需要有0个操作。字符串一样

B处: 表示ab 和a 需要有1个操作。

C处: 表示abe 和a 需要有2个操作。

D处: 表示a 和ab 需要有1个操作。

E处: 表示ab 和ab 需要有0个操作。字符串一样

F处: 表示abe 和ab 需要有1个操作。

G处: 表示a 和abc 需要有2个操作。

H处: 表示ab 和abc 需要有1个操作。

I处: 表示abe 和abc 需要有1个操作。


g.计算相似度

先取两个字符串长度的最大值maxLen,用1-(需要操作数除maxLen),得到相似度。

例如abc 和abe 一个操作,长度为3,所以相似度为1-1/3=0.666。

4.代码实现

直接能运行, 复制过去就行。

Java代码


package code;

/**

* @className:MyLevenshtein.java

* @classDescription:Levenshtein Distance 算法实现

* 可以使用的地方:DNA分析   拼字检查   语音辨识   抄袭侦测

* @author:donghai.wan

* @createTime:2012-1-12

*/

public class MyLevenshtein {

public static void main(String[] args) {

//要比较的两个字符串

String str1 = "今天星期四";

String str2 = "今天是星期五";

levenshtein(str1,str2);

}

/**

*   DNA分析   拼字检查   语音辨识   抄袭侦测

*

* @createTime 2012-1-12

*/

public static void levenshtein(String str1,String str2) {

//计算两个字符串的长度。

int len1 = str1.length();

int len2 = str2.length();

//建立上面说的数组,比字符长度大一个空间

int[][] dif = new int[len1 + 1][len2 + 1];

//赋初值,步骤B。

for (int a = 0; a <= len1; a++) {

dif[a][0] = a;

}

for (int a = 0; a <= len2; a++) {

dif[0][a] = a;

}

//计算两个字符是否一样,计算左上的值

int temp;

for (int i = 1; i <= len1; i++) {

for (int j = 1; j <= len2; j++) {

if (str1.charAt(i - 1) == str2.charAt(j - 1)) {

temp = 0;

} else {

temp = 1;

}

//取三个值中最小的

dif[i][j] = min(dif[i - 1][j - 1] + temp, dif[i][j - 1] + 1,

dif[i - 1][j] + 1);

}

}

System.out.println("字符串\""+str1+"\"与\""+str2+"\"的比较");

//取数组右下角的值,同样不同位置代表不同字符串的比较

System.out.println("差异步骤:"+dif[len1][len2]);

//计算相似度

float similarity =1 - (float) dif[len1][len2] / Math.max(str1.length(), str2.length());

System.out.println("相似度:"+similarity);

}

//得到最小值

private static int min(int... is) {

int min = Integer.MAX_VALUE;

for (int i : is) {

if (min > i) {

min = i;

}

}

return min;

}

}

5.猜测原理

为什么这样就能算出相似度了?

首先在连续相等的字符就可以考虑到

红色是取值的顺序。


1.今天周一 天周一

0123
1123
2123
3213
4331
实现是去掉“今”,一步完成。


2.听说马上就要放假了 你听说要放假了

01234567
11123456
22212345
33322345
44433345
55544445
66654555
77765456
88876546
99987664
这两个字符串是:

去掉“你”,加上“马上就”,总共四步操作。


3.还是没弄懂

6.结束

算法优化空间很大。

最后也没弄懂为什么这样算能算出相似度。

7



0



分享到:




StringUtils源码理解(下) | StringUtils源码理解(中)有点意思的方法

2012-01-13 00:42

浏览 31103

评论(11)

分类:编程语言

相关推荐


评论


11 楼 xu-ch 2013-07-20
今天面试,遇到这题,求出了相似度,面试官问我算法原理是什么,悲催的我没有答上来

10 楼 flywangfei 2013-06-08
你是创新工场的么?

9 楼 beike 2013-03-30
mark

8 楼 yangxiutian 2012-01-13
算法、数据结构 很重要 可是没掌握啊

7 楼 wdhdmx 2012-01-13

wangchen.ily 写道

g.计算相似度

先取两个字符串长度的最大值maxLen,用需要操作数除maxLen,得到相似度。

例如abc 和abe 一个操作,长度为3,所以相似度为1/2=0.666

有问题吧:

例如abc和abe maxLen=3 需要操作数是1

应该是1/3=0.333

谢谢提出来,大意了。我已经改回来了。

6 楼 wangchen.ily 2012-01-13
g.计算相似度

先取两个字符串长度的最大值maxLen,用需要操作数除maxLen,得到相似度。

例如abc 和abe 一个操作,长度为3,所以相似度为1/2=0.666

有问题吧:

例如abc和abe maxLen=3 需要操作数是1

应该是1/3=0.333

5 楼 wwsnowfoxww 2012-01-13
没有看懂什么意思

4 楼 wdhdmx 2012-01-13
我写错了,不是相似度,是 “最少编辑操作次数”。 为什么用这个方法能算出最少编辑次数,

相似度这个我理解了,已经。

3 楼 ansjsun 2012-01-13

Java代码


System.out.println("字符串\""+str1+"\"与\""+str2+"\"的比较");

//取数组右下角的值,同样不同位置代表不同字符串的比较

System.out.println("差异步骤:"+dif[len1][len2]);

//计算相似度

float similarity =1 - (float) dif[len1][len2] / Math.max(str1.length(), str2.length());

我觉得吧...首先他是一个参考前面过程的算法...当到了最后就是dif[len1][len2]的时候..就是最终的差异值....这个差一值越大肯定就越不一样

然后根据..差异值比上文本长度.. 被1减去 ..所以越趋近于1..说明文本越相似...

2 楼 liuningbo 2012-01-13


尴尬·

1 楼 ansjsun 2012-01-13


最后一句我彻底凌乱了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: