例如:源串”hello”,目标串”lleo”,则通过3次修改可以使得源串变成目标串(删除’h',删除’e',在’o'之前插入字符’e')
分析:这和编程之美中求两串的最长子序列很类似,我们同样采用动态规划的方法求解。首先需要确定的是该题的最优子结构,然后用普通的循环,或递归,或备忘录的方式来实现。设f[i][j]表示源串strA[1..i]变成目标串strB[1..j]所需改动的最小次数,当i=0时表示源串没有字符那么f[0][j]=j;当j=0时,表示目标串没有字符,所以f[i][0]=i;(在动态规划算法中这个初始化,或者叫边界条件很重要!);如果strA[i]==strB[j]那么f[i][j]=f[i-1][j-1];如果不等那么可以有三种办法
1.插入一个相同的字符,对应的f[i][j]=f[i][j-1]+1;
2.删除那个不同的字符,对应的f[i][j]=f[i-1][j]+1;
3.替换一个相同的字符,对应的f[i][j]=f[i-1][j-1]+1;
这样原理弄清楚了,开始写代码了:
代码如下:
// [10/7/2013 qingezha].给定一个源串和目标串,能够对源串进行如下操作: //在给定位置上插入一个字符 // 2).替换任意字符 // 3).删除任意字符 // 写一个程序,返回最小操作次数,使得对源串进行这些操作后等于目标串。 // 例如:源串”hello”,目标串”lleo”,则通过3次修改可以使得源串变成目标串(删除’h',删除’e',在’o'之前插入字符’e') //也可以通过找到最长公共字串,然后2个原来串的长度和减去公共字串的长度即可 int cal_distance(const char *sta,const char *stb) { if(sta == NULL || stb == NULL) return 0; int f[10+1][5+1]={0}; //这里可以用new一个一维数组,代替栈上的二维数组,因为栈上的编译时就确定长度,堆上的运行时才确定 //这里纯用于测试 for (int i=0;i<11;++i) f[i][0]=i; //悲剧啊,这里误写成0 了 for (int i=0;i<6;++i) f[0][i]=i; //悲剧啊,这里误写成0 了 int temp = 0; for (int j=1;j<6;++j) { for (int i=1;i<11;++i) //j<6写成了i<6,以后要小心啊 { if(sta[i]==stb[j]) f[i][j]=f[i-1][j-1]; else { temp = min(f[i-1][j-1]+1,f[i-1][j]+1); f[i][j]=min(f[i][j-1]+1,temp); } cout<<i<<" "<<j<<" "<<f[i][j]<<endl; } } return f[10][5]; }
以下是求最长公共字串代码:
// [7/7/2013 qingezha] 动态规划 最长公共子序列 c[i][j]表示Xi={x1,x2,x3。。。xi}与Yj={y1,y2,。。。yj}的最长公共字串序列的长度 int lcs_length(char x[],char y[],int b[LA+1][LB+1],int c[LA+1][LB+1]) { for (int i=1;i<=LA;++i) c[i][0]=0; //数组需要初始化,否则值不一定 for (int i=1;i<=LB;++i) c[0][i]=0; for (int i=1;i<=LA;++i) { for (int j=1;j<=LB;++j) { if (x[i]==y[j]) //序列从1开始计数 { c[i][j]=c[i-1][j-1]+1;//把c[i][j] 写成了c[i][i]了,重大失误,造成4个小时的浪费 b[i][j]=1; //b记录c的值由哪一个子问题的解得到的 } else if(c[i-1][j]>=c[i][j-1]) { c[i][j]=c[i-1][j]; b[i][j]=2; } else { c[i][j]=c[i][j-1]; b[i][j]=3; } } } ////////测试代码////////////////////////////////////////////////////////////////// for (int i=1;i<=LA;++i) //可以将数据输出来看看,哪里有不符合逻辑的错误 { for (int j=1;j<=LB;++j) { cout<<b[i][j]; } cout<<endl; } cout<<endl; for (int i=1;i<=LA;++i) { for (int j=1;j<=LB;++j) { cout<<c[i][j]; } cout<<endl; } cout<<endl; char x[7+2]=" abcdefx"; char y[7+2]=" aecxdfx"; int b[8][8]={{0}}; int c[8][8]={{0}}; int a[8]={0}; cout<<lcs_length(x,y,b,c)<<endl; lcs(7,7,x,b); ////////////////////////////////////////////////////////////////////////// return c[LA][LB]; } void lcs(int i,int j,char x[],int b[LA+1][LB+1])//输出最长的公共字串 { if(0==i||0==j) return; if (b[i][j]==1) { lcs(i-1,j-1,x,b); cout<<x[i]<<" "; } else if(2==b[i][j]) lcs(i-1,j,x,b); else lcs(i,j-1,x,b); }