您的位置:首页 > 编程语言 > Java开发

最短编译距离(Minimum Edit Distance)算法及java实现

2014-01-07 17:29 495 查看
最近学习一些查询纠错的问题,用到此算法,因此,在网上找了许多资料(其实详尽资料不多),并加入自己的一些理解,具体描述如下:
  最短编译距离给定任意两个字符串,比如:str1=“abcd”和str2=“gbcdz”,计算这两个字符串间的相似度。计算两字符串的相似度可等价于计算将str1变换到str2所需要的最少步骤。

  问题分析:

  为计算将str1变换到str2所需最小操作步骤,必须先对变换操作进行定义:

  1.修改一个字符(如把“a”替换为“g”);

  2.增加一个字符(如把“abcd”变为“abcdz”);

  3.删除一个字符(如把“travelling”变为“traveling”);

  字符串变换过程中执行了上述三个操作之间的任一操作,则两字符串间距离就加1。例如将上文中的str1变换到str2,即“abcd”到“gbcdz”,通过“abcd”->(操作1)->“gbcd”->(操作2)->“gbcdz”,需进行一次修改和一次添加字符操作,故两字符串距离为2,那么字符串相似度则为距离+1的倒数,即1/3=0.333。这是由俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。因此也叫Levenshtein Distance。

  那么如果给定两个任意字符串,如何计算它们距离呢?

  问题解决:

  解决此问题最好的方法是采用动态规划的方法。如下:

  设str1=“abcd”,str2=“gbcdz”,定义一个二维数组d[][],d[i][j]表示str1中取前i个字符和str2中取前j个字符的最短距离,例如d[3][2]表示“abc”到“gb”的最短距离。

  d[i][j]的计算规则有三条:

  来自d[i - i][j - 1],即 “str1的前i-1个字符组成的子串” 到 “str2的前j-1个字符组成的子串” 的最小距离,此时如果str1[i] = str2[j],则最短距离不变,否则最短距离加1(即把str1[i]变为str2[j] ),所以d[i][j] = d[i - 1][j - 1] + (str1[i] == str2[j] ? 0 : 1)

  来自d[i - 1][j],即 “A的前i-1个字符组成的子串” 到 “B的前j个字符组成的子串” 的编辑距离。此时删除在A的第i个位置上的字符即可,所以d[i][j] = d[i - 1][j] + 1

  来自d[i][j - 1], 即 “A的前i个字符组成的子串” 到 “B的前j-1个字符组成的子串” 的编辑距离。此时在A的子串后面添加一个字符B[j]即可,所以d[i][j] = d[i][j - 1] + 1

  于是状态转移方程:d[i][j] = min (d[i - 1][j - 1] + (str1[i] == str2[j] ? 0 : 1) , d[i - 1][j] + 1 , d[i][j - 1] + 1)

  例如str1=“abcd”,str2=“gbcdz”的d[][]就为(注意i,j的取值范围):将str1转化为str2所用编译距离为3,详细如下所示:

0 1 2 3 4 5

1 2 3 4 5 6

2 3 2 3 4 5

3 4 3 2 3 4

4 5 4 3 2 3

java的代码实现

public class MinimumEditDistance {

public static void main(String[] args) {

MinimumEditDistance med = new MinimumEditDistance();

med.min_edit_dic("abcd", "gbcdz");

}

public int min_edit_dic(String target, String source) {

int n = target.length();

int m = source.length();

int[][] distance = new int[n + 1][m + 1];

distance[0][0] = 0;

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

distance[i][0] = distance[i - 1][0]

+ ins_cost(target.charAt(i - 1));

}

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

distance[0][j] = distance[0][j - 1]

+ ins_cost(source.charAt(j - 1));

}

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

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

int ins = distance[i - 1][j] + ins_cost(target.charAt(i - 1));

int sub = distance[i - 1][j - 1]

+ subs_cost(target.charAt(i - 1), source.charAt(j - 1));

int del = distance[i][j - 1] + del_cost(source.charAt(j - 1));

distance[i][j] = min(ins, min(sub, del));

}

}

for (int i = 0; i <= n; i++) {

for (int j = 0; j <= m; j++) {

System.out.print(distance[i][j] + "\t");

}

System.out.println();

}

return 1;

}

private int min(int d1, int d2) {

return d1 < d2 ? d1 : d2;

}

private int ins_cost(char c) {

return 1;

}

private int del_cost(char c) {

return 1;

}

private int subs_cost(char c1, char c2) {

return c1 != c2 ? 2 : 0;

}

}
输出结果如上所示
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: