参考书目:《算法的乐趣》作者: 王晓华
参考博文:两个字符串的编辑距离-动态规划方法
动态规划是解决多阶段决策问题常用的最优化理论,由美国数学家Bellman等人在1957年提出,用于研究多阶段决策过程的优化问题。
适合求解多阶段(状态转移)决策问题的最优解,也可用于含线性问题或非线性递推关系的最优解问题。需满足以下两个特性。
最优化原理:不管之前的决策是否是最优决策,都必须保证从现在开始的决策是在之前决策基础上的最优决策。
无后向性(无后效性):每个阶段的决策仅受之前决策的影响,但是不影响之后各阶段的决策。
一般有四个步骤:定义最优子问题->定义状态->定义决策和状态转换方程->确定边界条件
两个字符的相似度定义为:将一个字符串转换成另一个字符串时需要付出的代价。其中,字符串的操作包括以下三种:
- 删除一个字符 a) Insert a character
- 插入一个字符 b) Delete a character
- 修改一个字符 c) Replace a character
首先用朴素的递归算法实现
/* 2018-3-22 朴素的递归算法实现:字符串的编辑距离 copyright @GCN */ #include<stdio.h> #include<stdlib.h> #include<string.h> int min(int a,int b) { if(a>b) return b; else return a; } int EditDistance(char *src,char *dest) { if(strlen(src)==0||strlen(dest)==0) return abs(strlen(src)-strlen(dest)); if(src[0]==dest[0]) return EditDistance(src+1,dest+1); int edIns=EditDistance(src,dest+1)+1;//source insert int edDel=EditDistance(src+1,dest)+1;//source delete int edRep=EditDistance(src+1,dest+1)+1;//source replace return min(min(edIns,edDel),edRep); } int main() { char *src="SNOWY"; char *dest="sunny"; int cost; cost=EditDistance(src,dest); printf("the final answer is %d\n",cost); return 0; }
(发现两次结果不一样,还以为写错了。呃,原来是我输入的字符串的大小写问题。)
然后用动态规划对朴素的递归算法进行改进
/* 2018-3-23 动态规划:字符串的编辑距离 copyright @GCN */ #define MAX_STRING_LEN 100 #include<stdio.h> #include<stdlib.h> #include<string.h> int min(int a,int b) { if(a<b) return a; else return b; } int EditDistance(char *src,char *dest) { int i,j; int d[MAX_STRING_LEN][MAX_STRING_LEN]={0xFFFF}; int edIns,edDel,edRep; for(i=0;i<=strlen(src);i++) d[i][0]=i; for(j=0;j<=strlen(dest);j++) d[0][j]=j; for(i=1;i<=strlen(src);i++) { for(j=1;j<=strlen(dest);j++) { if((src[i-1]==dest[j-1])) d[i][j]=d[i-1][j-1];//字符匹配,不需要任何操作 else { edIns=d[i][j-1]+1;//source 插入字符 edDel=d[i-1][j]+1;//source 删除字符 edRep=d[i-1][j-1]+1;//source 替换字符 d[i][j]=min(min(edIns,edDel),edRep); } } } return d[strlen(src)][strlen(dest)]; } int main() { char *src="SNOWY"; char *dest="SUNNY"; int cost=EditDistance(src,dest); printf("the final result is %d\n",cost); return 0; }