您的位置:首页 > 其它

最小编辑距离 | Minimum Edit Distance

2016-08-22 22:05 302 查看
关于两个字符串s1,s2的差别,可以通过计算他们的最小编辑距离来决定。

设A、B为两个字符串,狭义的编辑距离定义为把A转换成B需要的最少删除(删除A中一个字符)、插入(在A中插入一个字符)和替换(把A中的某个字符替换成另一个字符)的次数,用ED(A,B)来表示。直观来说,两个串互相转换需要经过的步骤越多,差异越大。

对于编辑距离的状态转移较为难想。

正确的思路应当是将s1的前i位数据转换成s2的前j位数据所需要的转换步数设置为dp[i][j]



如上图,由上往下表示添加,例如a->azc

由左往右表示删除,例如abc->a

斜向下表示更新,例如abc->azc

于是某一点的最小编辑距离首先需要考虑的是s[i]==s2[j]??

如果相等,则考虑d[i][j]=dp[i-1][j-1];也即这一位不需要进行变换。

而不相等的时候,需要进行变换,并寻找如何才能在最短的步数完成变换。

故有3条方式:以ab->az为例

不考虑b的时候,a->az = 1,故ab->az = 2 ,也即在a->az基础上添加b

不考虑z的时候,ab->a = 1,故ab->az = 2 , 也即在a->az基础上删除b,添加z,一共2步

不考虑b和z的时候,a->a = 0, 故ab->az=1,也即在a->a基础上,将b->z 一共1步

//说实话这个挺晦涩,过几天再好好总结一下

不过这样一来DP方程倒是比较简单了。

s[i]==s[j]时,dp[i][j]=dp[i-1]][j-1]

s[i]!=s[j]时,dp[i][j]=min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1])

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<vector>
#include<string>
using namespace std;

int min(int a,int b,int c){
int d=a>b?b:a;
return d>c?c:d;
}

class Solution{
public:
int generate(string s1,string s2){
int m=s1.size();
int n=s2.size();
int dp[m+1][n+1];
memset(dp,0,sizeof(dp));
for(int i=0;i<=n;i++) dp[0][i]=i;
for(int i=0;i<=m;i++) dp[i][0]=i;

for(int i=0;i<s1.size();i++){
for(int j=0;j<s2.size();j++){
if(s1[i]==s2[j]){
dp[i+1][j+1]=dp[i][j];
}
else{
dp[i+1][j+1]=min(dp[i+1][j],dp[i][j+1],dp[i][j])+1;
}
}
}
return dp[m]
;
}
};

int main(){
string s1="abcdef";
string s2="a3ced";
Solution solution;
int val=solution.generate(s1,s2);

printf("val %d\n",val);
system("pause");
return 0;
}


不过既然准备把它总结到坐标DP里面,就先来抛个砖:

坐标类动态规划有一个共性,那就是在一个矩阵中(一般是二维矩阵,当然可能有更加复杂的图形)给出一些规则,然后按规则去做某些决策,我们思考这类问题的基本方法是:以坐标为状态,坐标之间的转换关系,一般利用问题给出的规则进行决策转移。




也就是说,dp[i][j]的状态不仅仅像线性DP或者区间DP那种可以使用一个一维数组反复使用上一步的步骤,其[i][j]步所依赖的状态与矩阵上的数据和已经走过的矩阵部分密切相关。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: