Description
俄罗斯科学家Vladimir Levenshtein在1965年提出了编辑距离概念。编辑距离,又称Levenshtein距离,是指两个字符串之间,由一个转成另一个所需的最少编辑操作次数。许可的三种编辑操作包括插入一个字符、删除一个字符、将一个字符替换成另一个字符。
至今,编辑距离一直在相似句子检索的领域中发挥着不可忽视的作用。
我们不妨来设计一个程序,计算两个字符串的编辑距离。
Input
每组数据有两行,每行一个字符串。
* 每个字符串长度不超过1000
* 字符串中只含小写英文字母
Output
对于每组数据,请输出一个整数表示两个字符串的编辑距离。
分析问题:
1.当a,b 只有两个字符串都只有一个字符时,非常简单,当a=b时,返回0,a!=b时返回1;
2.当a是一个字符,b是一个字符串时,a与b[1]相同则记为 编辑距离为t=0,反之t=2,a与b[2]比较,a=b[2]:t=t+1;
a!=b[2]:t=t;------->a=b[i]:t=t+1;a!=b[i]:t=t;最后编辑距离为t;
3.但是a='a',b='aa'时按2中方法是t=0;编辑距离确实为1。对于两个字符串,编辑距离肯定大于等于两字符串长度差的绝对值。
4,我们分析一下以下几个表:
a | b | a | b | a | b | a | b | ||||
a | 0 | 1 | c | 1 | 2 | b | 1 | 1 | c | 1 | 2 |
b | 1 | 0 | d | 2 | 2 | c | 2 | 2 | b | 2 | 1 |
a | b | c | a | b | c | a | b | c | a | b | c | ||||
c | 1 | 2 | 2 | c | 1 | 2 | 2 | b | 1 | 1 | 2 | b | 1 | 1 | 2 |
b | 2 | 1 | 2 | a | 1 | 2 | 3 | a | 1 | 2 | 2 | c | 2 | 2 | 1 |
a | 2 | 2 | 2 | c | 2 | 2 | 2 | c | 2 | 2 | 2 | d | 3 | 3 | 2 |
观察两个表中的编辑距离,可以发现规律:
则f[j,k]为f[j-1,k-1]、f[j-1,k]、f[j,k-1]三个数中最小数+1
则f[j,k]=f[j-1,k-1]
若j=1且k≠1则f[j,k]=f[j,k-1]+1
若k=1且j≠1则f[j,k]=f[j-1,k]+1
若j=1且k=1则f[1,1]=1
若j=1且k≠1则f[j,k]=f[j,k-1]
若k=1且j≠1则f[j,k]=f[j-1,k]
若k=1且j=1则f[1,1]=0
c语言代码实现:
#include<stdio.h>
#include<string.h>
#include<math.h>
int min_one(int left,int middle,int right) ;
int compare_Distance(char strA[],char strB[]);
int main()
{
int distance;
char a[100],b[100];
gets(a); //输入两组字符串
gets(b);
distance=compare_Distance(a,b); //调用compare_Distance函数计算编辑距离
printf("%d\n",distance);
return 0;
}
int min_one(int left,int middle,int right)
{
int min_one;
if(left<=middle&&left<=right)
min_one = left; //最右边的是最小的一个
else if
(middle<=right&&middle<=left) min_one=middle; //中间的一个是最小的一个
else
min_one = right; //右边的是最小的一个
return(min_one);
}
int compare_Distance(char strA[],char strB[])
{
int i,j;
int m=strlen(strA);
int n=strlen(strB);
int L[100][100];
if(strA[0]==strB[0])
L[0][0]=0;
else
L[0][0]=1;
for( i=1;i<m;i++) //定义第一行的距离为0到m-1
{
if(strA[i]==strB[0])//分两种情况
L[i][0]=L[i-1][0];
else
L[i][0]=L[i-1][0]+1;
}
for( j=1;j<n;j++) //定义第一列的距离为0到n-1
{
if(strA[0]==strB[j])//分两种情况
L[0][j]=L[0][j-1];
else
L[0][j]=L[0][j-1]+1;
}
for(i=1;i<m;i++)
for(j=1;j<n;j++)
{
if(strA[i]==strB[j])
L[i][j]=L[i-1][j-1]; //两个字符相同就等于上一个的距离。
else
L[i][j]=min_one(L[i-1][j-1],L[i-1][j],L[i][j-1])+1; //如果两个字符不相同,就是前三个最小的一个的距离。
}
// for(i=0;i<m;i++){
//for(j=0;j<n;j++)
//printf("%d ",L[i][j]);
//printf("\n");
}
if(L[m-1][n-1]<abs(m-n))//解决当编辑距离小于两字符串长度差的问题
L[m-1][n-1] = abs(m-n);
return L[m-1][n-1];
}