编辑距离(Edit Distance),又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
下图为计算字符“beauty”与“batyu”编辑距离的二维图解:
步骤详解:1)先建立一张二维表(矩阵),如上图所示。矩阵中(0,0)位置不对应字母。
2)计算矩阵(1,1)位置(即:红圈1所在的置)的值,此处为方便描述,将该位置定义为A点。
A点的值需要由A点左上方、左边和上边的值共同决定。为方便描述先将A点所需要的三个值赋给变量a,则a=(0,1,1)
A点对应的字母分别为(b,b),字母相同,则A点左上角的值加0(不同则加1),A点左边与上边的值分别加1。
此时a=(0,2,2),取a中做小值填入A点位置,见右图所示。
矩阵(1,2)位置(即:红圈2所在的位置),定义为B点。
B点赋值为b=(1,0,2)。由于B点对应的字母为(b,e),字母不同,则B点左上角的值加1,同时,B点左侧上侧分别加1。
此时b=(2,1,3),取b中最小值赋给B点。
3)按照步骤2)求出每个格子中的值。所有值求出后,右下角的值为最小编辑距离。
注意:不管上述步骤中的A点对应的字母(b,b)或B点对应的字母(b,e)是否相同,左侧和上侧都需要加1。
对于序列S和T,它们之间距离定义为:对二者其一进行几次以下的操作(1)删去一个字符;(2)插入一个字符;(3)改变一个字符。每进行一次操作,计数增加1。将S和T变为同一个字符串的最小计数即为它们的距离。给出相应算法。
解法:
将S和T的长度分别记为len(S)和len(T),并把S和T的距离记为m[len(S)][len(T)],有以下几种情况:
如果末尾字符相同,那么m[len(S)][len(T)]=m[len(S)-1][len(T)-1];
如果末尾字符不同,有以下处理方式
修改S或T末尾字符使其与另一个一致来完成,m[len(S)][len(T)]=m[len(S)-1][len(T)-1]+1;
在S末尾插入T末尾的字符,比较S[1...len(S)]和S[1...len(T)-1];
在T末尾插入S末尾的字符,比较S[1...len(S)-1]和S[1...len(T)];
删除S末尾的字符,比较S[1...len(S)-1]和S[1...len(T)];
删除T末尾的字符,比较S[1...len(S)]和S[1...len(T)-1];
总结为,对于i>0,j>0的状态(i,j),m[i][j] = min( m[i-1][j-1]+(s[i]==s[j])?0:1 , m[i-1][j]+1, m[i][j-1] +1)。
这里的重叠子结构是S[1...i],T[1...j]。
import java.util.*;
public class 字符串相似度or编辑距离 {
public static int min(int a,int b,int c) {
int min=Integer.MAX_VALUE;
if(a<min)
min=a;
if(b<min)
min=b;
if(c<min)
min=c;
return min;
}
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
String[] s=new String[2];
while(in.hasNext()) {
s=in.nextLine().split(" ");
String s1=s[0];
String s2=s[1];
int m=s1.length(),n=s2.length();
int temp; //记录相同字符,不是0就是1
char c1,c2;
if(m==0||n==0)
System.out.println(0);
int[][] dp=new int[m+1][n+1];
for(int i=0;i<=m;i++) //初始化第一行
dp[i][0]=i;
for(int j=0;j<=n;j++) //初始化第二行
dp[0][j]=j;
for(int i=1;i<=m;i++) { //遍历两个字符串
c1=s1.charAt(i-1);
for(int j=1;j<=n;j++) {
c2=s2.charAt(j-1);
if(c1==c2) //如果某一位置上的字符相同,不需要操作temp=0
temp=0;
else //如果某一位置上的字符不同,需要操作temp=1
temp=1;
//找到每一步编辑变化的最小值
dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+temp);
}
}
System.out.println(dp[m][n]);
}
}
}