import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
/**
* 编辑距离,又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。
* 许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
*
* 俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。
*
* 问题:找出字符串的编辑距离,即把一个字符串s1最少经过多少步操作变成字符串s2? (操作有三种,添加一个字符,删除一个字符,修改一个字符)
*
* 解析:首先定义这样一个函数——edit(i, j),它表示第一个字符串的长度为i的子串到第二个字符串的长度为j的子串的编辑距离。
显然可以有如下动态规划公式:
① if i == 0 且 j == 0,edit(i, j) = 0;
② if i == 0 且 j > 0,edit(i, j) = j;
③ if i > 0 且j == 0,edit(i, j) = i;
④ if i ≥ 1 且 j ≥ 1 ,edit(i, j) == min {
edit(i-1, j) + 1,
edit(i, j-1) + 1,
edit(i-1, j-1) + f(i, j)
},当第一个字符串的第i个字符不等于第二个字符串的第j个字符时,f(i, j) = 1;否则,f(i, j) = 0。
*
* 两比较字符串的初始二维距离表:
0 f a i l i n g
* 0
* s
* a
* i
* l
* n
*
* 经过①②③步动态规划处理后二维距离表:
* 0 f a i l i n g
* 0 0 1 2 3 4 5 6 7
* s 1
* a 2
* i 3
* l 4
* n 5
*
* 带入动态规划计算 edit(1, 1):
* edit(0, 1) + 1 == 2,
* edit(1, 0) + 1 == 2,
* edit(0, 0) + f(1, 1) == 0 + 1 == 1,
* min(edit(0, 1),edit(1, 0),edit(0, 0) + f(1, 1))==1,因此edit(1, 1) == 1。
* 依次类推有:
*
* 0 f a i l i n g
0 0 1 2 3 4 5 6 7
s 1 1 2 3 4 5 6 7
a 2 2 1 2 3 4 5 6
i 3 3 2 1 2 3 4 5
l 4 4 3 2 1 2 3 4
n 5 5 4 3 2 2 2 3
*
* 编辑距离
*
* @author pjm0008
*
* @version 1.0 bate
*
* 2015年12月31日
*/
public class LevensheinDistance {
public static void main(String [] args) {
String a = readFile("D:/c.txt");
String b = readFile("D:/d.txt");
levensDist(a,b);
String c = "http://www.163.com";
String d = "http://www.126.com";
levensDist(c,d);
}
public static void levensDist (String a, String b) {
int max = max(a.length(),b.length());
int x = edit(a,b);
int y = (max-x)*100/max;
System.out.println("所需编辑次数:" + x + ",相似度:" + y + "%");
}
public static int min (int a, int b) {
return a < b ? a : b;
}
public static int max (int a, int b) {
return a > b ? a : b;
}
public static int edit (String a, String b) {
int len1 = a.length();
int len2 = b.length();
int [][] matrix = new int[len1+1][len2+1];
for (int i = 0; i < len1 + 1 ; i ++) {
matrix[i][0] = i;
}
for (int j = 0; j < len2 + 1; j ++) {
matrix[0][j] = j;
}
for (int k = 1; k < len1 + 1; k ++) {
for (int x = 1; x < len2 + 1; x ++) {
int f = 1;
if (a.charAt(k-1) == b.charAt(x-1)) {
f = 0;
}
matrix[k][x] = min(min(matrix[k-1][x]+1,matrix[k][x-1]+1),
matrix[k-1][x-1] + f);
}
}
return matrix[len1][len2];
}
public static String readFile (String file) {
if (null == file || !(new File(file)).exists()) {
return null;
}
String tmp = null;
StringBuffer sb = new StringBuffer();
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));
while ((tmp = br.readLine()) != null) {
sb.append(tmp).append(System.lineSeparator());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
}