编辑距离(Levenshtein):两个字符之间有一个转成另一个所用的最少的编辑操作次数,操作包括:替换、插入、删除一个字符。
定义:
原理:
首先考虑极端情况,当或长度为0时,那么需要编辑的次数就是里一个字符串的长度。
然后再考虑一般情况,此时分为三种情况:
在k个操作中,将a[1...i]转换为b[1...j-1]:例如:a(abc) b(abcd)
在k个操作中,将a[1...i-1]转换为b[1...j]:例如:a(abc) b(ab)
在k个操作中,将a[1...i-1]转换为b[1...j-1]:例如:a(abc) b(abb)
针对第一种情况,只需要在a[1...i]后加上字符b[j],即可完成a[1..i]到b[1...j]的转换,总共需要的编辑次数即为k+1。
针对第二种情况,只需要在a[i]字符从a中移除,即可完成a[1..i]到b[1...j]的转换,总共需要的编辑次数即为k+1。
针对第三种情况,只需要将a[i]转换为b[j],即可完成a[1..i]到b[1...j]的转换,如果a[i]与b[i]的字符相同,则总共需要的编辑次数为k,否则即为k+1。
所以上述三种情况分别对应于插入、删除、替换操作。
为了保证将a[1..i]转换为b[1..j]的操作数总是最少的,只需要从三种情况中选择操作次数最少的情况,同理为了保证三种情况的操作数也是最小的,只需要按此逻辑进行迭代保证每一步的操作数都是最小的即可。
String left="helloword"; String right="hellowo";
代码:
package com.parse;
public class Test3 {
public static void main(String args[]){
String left="helloword";
String right="hellowo";
int maxLength = Math.max(left.length(), right.length());
//计算编辑距离
double lev = unlimitedCompare(left, right);
System.out.println("编辑距离:"+lev);
//计算相似度
double levNorm = 1 - (lev / maxLength);
System.out.println("相似度:"+levNorm);
}
public static int unlimitedCompare(CharSequence left, CharSequence right) {
if (left == null || right == null) {
throw new IllegalArgumentException("Strings must not be null");
}
int n = left.length();
int m = right.length();
//如果有一个String长度为0,则编辑长度为另一个String长度
if (n == 0) {
return m;
} else if (m == 0) {
return n;
}
int [][] dp = new int [n+1][m+1]; //动态规划数组
int i;//left的索引
int j;//right的索引
char leftI; // left字符串第i项字符
char rightJ; // right字符串第j项字符
int cost; //操作代价
//初始化第一列
for (i = 0; i <= n; i++)
{
dp[i][0] =i;
}
//初始化第一行
for (j = 0; j <= m; j++)
{
dp[0][j] = j;
}
for (i = 1; i <= n; i++) {
leftI =left.charAt(i - 1);
for (j = 1; j <= m; j++) {
rightJ = right.charAt(j - 1);
//从i看是否和rightJ相同,所需要的操作代价,不同就会+1,相同为0
cost = leftI == rightJ ? 0 : 1;
//取dp[i - 1][j] + 1,dp[i][j-1] + 1, dp[i-1][j-1] + cost这三者中最小的
dp[i][j] = Math.min(Math.min(dp[i - 1][j] + 1, dp[i][j-1] + 1), dp[i-1][j-1] + cost);
}
}
return dp[n][m];
}
}
感觉理解了? 想想下面的编辑距离为啥是2,而不是3?
String left="abroad"; String right="aboard";
String left="abroad"; String right="aboadr";
不理解的话,看看文章开头第一句话中的“最少”二字。