编辑距离

来源:互联网 发布:php交友网站源码 编辑:程序博客网 时间:2024/04/30 05:46

题目:

假设,字符串仅有三个基本操作:删除一个字符、插入一个字符和将一个字符修改成另一个字符。

基本的字符操作:进行了一次上述三种操作的任意一种操作

两个字符串的编辑距离的定义:通过上述的基本操作,我们可以把字符串a变成字符串b,所需要的最少基本字符操作次数

举例:snowy  与 sunny 的编辑距离为3

我们的任务:计算任意两个字符串的编辑距离

状态转移方程

d[ i ][ j ]:表示把源文本串X的前i个字符串转换为目标串Yj个字符串的最小代价

d[ i ][ j ] = min (d[i - 1][j - 1] + cost ,  d[i - 1][j]+1, d[i][j-1]+1)

其中,当 X[i] = Y[j]时,cost = 0。当 X[i]  != Y[j],cost = 1

注意:这三种情况都可以转化成d[ i ][ j ],它们是并列的,写状态转移方程时,所有能转化为d[ i ][ j ]的情况都要考虑到。

简单说明:如果取d[i][j - 1]最小,表示X[1 ~ i] 和 Y[1 ~ j - 1] 已经完全匹配,由于X的i个序列已经全部处理完毕,但是Y还剩一个,我们只需要在往X中添加一个元素Y[j]即可,此时X的前i个和Y的前j个就全部相等了

迭代代码

#include <iostream>using namespace std;const int MaxLen = 20;//char X[] = " snowy"; //char Y[] = " sunny";  char X[] = " interestingly"; char Y[] = " bioinformatics";  int d[MaxLen][MaxLen] = {{0}};void PrintD(int lenX,int lenY){for (int i = 0;i <= lenX;i++){for (int j = 0;j <= lenY;j++){cout<<d[i][j]<<" ";}cout<<endl;}}int Min(int x,int y,int z){if (x < y){if (x < z)  //  x < y{return x;}else     // z < x < y{return z;}}else{if (y < z)  //x > y{return y;}else        //x > y y >= z{return z;}}}// 处理过程中,我们只修改原始字符串,对该字符串增删改int EditDistance(int lenX,int lenY){int cost = 0;//初始化边界条件//X串有内容,Y串没有内容for (int i = 1;i <= lenX;i++){d[i][0] = i;//X串要变成Y串,每次需要在X串中删除一个字符 }//X串为空,Y有内容for (int j = 1;j <= lenY;j++){d[0][j] = j;//X串没内容,X串要变成Y,必须往X串中插入Y[i]}for (int i = 1;i <= lenX;i++){for (int j = 1;j <= lenY;j++){if (X[i] == Y[j]){cost = 0;}else{cost = 1;}int Replace = d[i - 1][j - 1] + cost;int Insert = d[i][j - 1] + 1;int Del = d[i - 1][j] + 1;d[i][j] = Min(Replace,Insert,Del);}}return d[lenX][lenY];}int main(){int lenX = strlen(X) - 1;int lenY = strlen(Y) - 1;cout<<EditDistance(lenX,lenY)<<endl;//PrintD(lenX,lenY);system("pause");return 0;}

注意一点:上述代码中,无论X[i] 与 Y[j]是否相等,都是进行了删除和添加操作。其实也可以在字符不等时,进行修改删除和添加操作。在字符相等时,不进行任何操作。d[i][j] = d[i - 1][j - 1].

备忘录

#include <iostream>using namespace std;const int MaxLen = 20;/*char X[] = " interestingly";   char Y[] = " bioinformatics";*/ char X[] = " snowy";    char Y[] = " sunny"; int d[MaxLen][MaxLen] = {{0}};int Min(int x,int y,int z){if (x < y){if (x < z)  //  x < y{return x;}else     // z < x < y{return z;}}else{if (y < z)  //x > y{return y;}else        //x > y y >= z{return z;}}}// 处理过程中,我们只修改原始字符串,对该字符串增删改int EditDistance(int i,int j){int cost = 0;if (d[i][j]){return d[i][j];}//边界条件if (i == 0 && j != 0){return d[i][j] = EditDistance(i,j - 1) + 1;//插入代价}if (i != 0 && j == 0){return d[i][j] = EditDistance(i - 1,j) + 1;//删除代价}if (!i && !j){return 0;}//正式处理if (X[i] == Y[j]){cost = 0;}else{cost = 1;}int Replace = EditDistance(i - 1,j - 1) + cost; int Insert = EditDistance(i,j - 1) + 1;  int Del = EditDistance(i - 1,j) + 1;return d[i][j] = Min(Replace,Insert,Del);}int main(){cout<<EditDistance(strlen(X) - 1,strlen(Y) - 1)<<endl;system("pause");return 0;}

递归暴力

#include <iostream>using namespace std;const int MaxLen = 20;//char X[] = " interestingly";   //char Y[] = " bioinformatics"; char X[] = " snowy";    char Y[] = " sunny"; int Min(int x,int y,int z){if (x < y){if (x < z)  //  x < y{return x;}else     // z < x < y{return z;}}else{if (y < z)  //x > y{return y;}else        //x > y y >= z{return z;}}}// 处理过程中,我们只修改原始字符串,对该字符串增删改int EditDistance(int i,int j){int cost = 0;//边界条件if (i == 0 && j != 0){return j;//插入代价}if (i != 0 && j == 0){return i;//删除代价}if (!i && !j){return 0;}//正式处理if (X[i] == Y[j]){cost = 0;}else{cost = 1;}int Replace = EditDistance(i - 1,j - 1) + cost; int Insert = EditDistance(i,j - 1) + 1;  int Del = EditDistance(i - 1,j) + 1;return Min(Replace,Insert,Del);}int main(){cout<<EditDistance(strlen(X) - 1,strlen(Y) - 1)<<endl;system("pause");return 0;}


 

原创粉丝点击