编辑距离

一、问题描述

设A和B是两个字符串。要用最少的字符操作将字符串A转换为字符串B。这里所说的字符操作包括:

<wbr>(1)删除一个字符;</wbr>

<wbr>(2)插入一个字符;</wbr>

<wbr>(3)将一个字符改为另一个字符;</wbr>

<wbr>将字符串A变换为字符串B所用的最少字符操作数称为字符串A到B的编辑距离,记为d(A,B)。试设计一个有效算法,对任给的两个字符串A和B,计算出它们的编辑距离d(A,B)。</wbr>

<wbr></wbr>

二、分析解答

设所给的两个字符串为A[1:m]和B[1:n]。定义D[i][j]=d(A[1:i],B[1,j])。单字符a,b间的距离定义为:

d(a,b)=0 (a=b)

d(a,b)=1(a!=b)

考察从字符串A[1:i]到字符串B[1:j]的变换。可分成以下几种情况:
(1)字符A[i]改为字符B[j];需要d(A[i],B[j])次操作。

(2)删除字符A[i];需要1次操作。

(3)插入字符B[j];需要1次操作。
因此,D[i][j]可递归地计算如下。

D[i][j]=min{D[i-1][j-1]+d(A[i],B[j]),D[i-1][j]+1,D[i][j-1]+1}。

<wbr></wbr>

三、算法描述

int dist(A[0…m-1],B[0…n-1])

{

int D[0…m,0…n]

int i,j,cost

对于i等于0至m

D[i, 0]=i

对于j等于0至n

D[0,j]=j

对于i等于1至m

<wbr><wbr><wbr>对于j等于1至n</wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr>若 A[i-1]=B[j-1]则cost=0 否则 cost=1</wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr>D[i][j]=min(D[i-1,j]+1,//删除</wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>D[i,j-1]+1,//插入</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>D[i-1,j-1]+cost//替换</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>)</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

返回d[m,n]

}

<wbr></wbr>

四、代码实现

定义一个二维数组D[][]存储中间结果,如下图所示,为已经初始化后的情况。然后从D[1,1]开始从左到右,从上到下依次按填表,表的最后一个元素D[m,n]就是要求的最终结果。

<wbr></wbr>

0

1

2

3

4

5

6

0

0

1

2

3

4

5

6

1

1

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

2

2

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

3

3

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

4

4

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

5

5

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

6

6

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

#include<iostream> #include<string> using namespace std; int D[100][100]; int dis[100]; int min(int a,int b,int c) { return c<(a>b?b:a)?c:(a>b?b:a); } int dist(char * A,char * B) { int m=strlen(A); int n=strlen(B); int i,j; for(i=0;i<=m;++i) { D[i][0]=i; } for(j=0;j<=n;++j) { D[0][j]=j; } int cost; for(i=1;i<=m;++i) { for(j=1;j<=n;++j) { if(A[i-1]==B[j-1]) cost=0; else cost=1; D[i][j]=min(D[i-1][j-1]+cost,D[i-1][j]+1,D[i][j-1]+1); } } return D[m][n]; } int dist2(char * A,char * B) { int m=strlen(A); int n=strlen(B); int i,j; for(i=0;i<=n;++i) dis[i]=i; int cost; for(i=1;i<=m;++i) { int y=i-1; for(j=1;j<=n;++j) { int x=y; y=dis[j]; int z=j>1?dis[j-1]:i; cost=A[i-1]==B[j-1]?0:1; dis[j]=min(x+cost,y+1,z+1); } } return dis[n]; } int main(int argc, char* argv[]) { char * ch1="bcdefghijklmnopq"; char * ch2="abcdefghijklmnopadfsafwe"; cout<<dist(ch1,ch2)<<endl; cout<<dist2(ch1,ch2)<<endl; return 0; }

package net.hr.algorithm.stroper; /** * 字符串编辑距离 * * 这是一种字符串之间相似度计算的方法。 * 给定字符串S、T,将S转换T所需要的插入、删除、替代操作的数量叫做S到T的编辑路径。 * 其中最短的路径叫做编辑距离。 * * 这里使用了一种动态规划的思想求编辑距离。 * * @author heartraid * */ public class StrEditDistance { /**字符串X*/ private String strX=""; /**字符串Y*/ private String strY=""; /**字符串X的字符数组*/ private char[] charArrayX=null; /**字符串Y的字符数组*/ private char[] charArrayY=null; public StrEditDistance(String sa,String sb){ this.strX=sa; this.strY=sb; } /** * 得到编辑距离 * @return 编辑距离 */ public int getDistance(){ charArrayX=strX.toCharArray(); charArrayY=strY.toCharArray(); return editDistance(charArrayX.length-1,charArrayY.length-1); } /** * 动态规划解决编辑距离 * * editDistance(i,j)表示字符串X中[0.... i]的子串 Xi 到字符串Y中[0....j]的子串Y1的编辑距离。 * * @param i 字符串X第i个字符 * @param j 字符串Y第j个字符 * @return 字符串X(0...i)与字符串Y(0...j)的编辑距离 */ private int editDistance(int i,int j){ if(i==0&&j==0){ //System.out.println("edit["+i+","+j+"]="+isModify(i,j)); return isModify(i,j); } else if(i==0||j==0){ if(j>0){ //System.out.println("edit["+i+","+j+"]=edit["+i+","+(j-1)+"]+1"); if(isModify(i,j) == 0) return j; return editDistance(i, j-1) + 1; } else{ //System.out.println("edit["+i+","+j+"]=edit["+(i-1)+","+j+"]+1"); if(isModify(i,j) == 0) return i; return editDistance(i-1,j)+1; } } else { //System.out.println("edit["+i+","+j+"]=min( edit["+(i-1)+","+j+"]+1,edit["+i+","+(j-1)+"]+1,edit["+(i-1)+","+(j-1)+"]+isModify("+i+","+j+")"); int ccc=minDistance(editDistance(i-1,j)+1,editDistance(i,j-1)+1,editDistance(i-1,j-1)+isModify(i,j)); return ccc; } } /** * 求最小值 * @param disa 编辑距离a * @param disb 编辑距离b * @param disc 编辑距离c */ private int minDistance(int disa,int disb,int disc){ int dismin=Integer.MAX_VALUE; if(dismin>disa) dismin=disa; if(dismin>disb) dismin=disb; if(dismin>disc) dismin=disc; return dismin; } /** * 单字符间是否替换 * * isModify(i,j)表示X中第i个字符x(i)转换到Y中第j个字符y(j)所需要的操作次数。 * 如果x(i)==y(j),则不需要任何操作isModify(i, j)=0; 否则,需要替换操作,isModify(i, j)=1。 * @param i 字符串X第i个字符 * @param j 字符串Y第j个字符 * @return 需要替换,返回1;否则,返回0 */ private int isModify(int i,int j){ if(charArrayX[i]==charArrayY[j]) return 0; else return 1; } /** * 测试 * @param args */ public static void main(String[] args) { System.out.println("编辑距离是:"+new StrEditDistance("eeba","abac").getDistance()); } }

<wbr></wbr>

五、优化方法

从上面算法可以看出,该算法时间复杂性为0(m*n),空间复杂性为O(m*n)。同时可以看出,当对第i行进行填表时,只需要用到第i-1行的数据,因此可以用一个一维数组dis[0…n]代替二维数组D[0…m,0…n],因此空间复杂性降为O(n)。实现代码如上面函数dist2()所示。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值