题目描述:给定一个源串和目标串,能够对源串进行如下操作:
1.在给定位置上插入一个字符
2.替换任意字符
3.删除任意字符
写一个程序,返回最小操作数,使得对源串进行这些操作后等于目标串,源串和目标串的长度都小于2000。
提醒:上文前言中已经说过了,此题反复出现,最近考的最多的是百度和Google的笔试面试经常考察。
分析:
修改一个字符(如把“a”替换为“b”);
增加一个字符(如把“abdd ”变为“aebdd ”);
删除一个字符(如把“travelling”变为“traveling”)。
比如,对于“abcdefg”和“abcdef ”两个字符串来说,我们认为可以通过增加/减少一个“g”的方式来达到目的。上面的两种方案,都仅需要一次操作。把这个操作所需要的次数定义为两个字符串的距离。
不难看出,两个字符串的距离肯定不超过他们的长度之和,所以,任意两个字符串的距离都是有限的。
如何把A变成B,考虑把这个问题转化为规模较小的同样的问题?可以分成如下的情况:
1:删除A[lenA],然后考虑将A[1..lenA-1]变为B[1..lenB]
2:添加B[lenB],然后考虑将A[1..lenA]变为B[1..lenB-1]
3:将A[lenA]替换为B[lenB],然后考虑将A[1..lenA-1]变为B[2..lenB-1]
那么,将A变成B,需要的最少步骤,就是上述3个过程的最小值。
此题跟LCS问题类似,常见的思路是动态规划这样,下面是简单的DP状态方程:
//f[i,j]表示s[0...i]到t[0...j]的最小编辑距离。
f[i,j] = min { f[i-1,j]+1, f[i,j-1]+1, f[i-1,j-1]+(s[i]==t[j]?0:1) }
很快就可以完成一个普通的递归程序,如下所示:int CalculateStringDistance(string strA, int pABegin, int pAEnd, string strB, int pBBegin, int pBEnd){
if(pABegin > pAEnd)
{
if(pBBegin > pBEnd)
return 0;
else
return pBEnd – pBBegin + 1;
}
if(pBBegin > pBEnd)
{
if(pABegin > pAEnd)
return 0;
else
return pAEnd – pABegin + 1;
}
if(strA[pAEnd] == strB[pBEnd])
{
int t0 = CalculateStringDistance(strA, pABegin, pAEnd-1, strB, pBBegin, pBEnd-1);
}
else
{
int t3 = CalculateStringDistance(strA, pABegin, pAEnd-1, strB,pBBegin, pBEnd-1);
}
int t1 = CalculateStringDistance(strA, pABegin, pAEnd, strB, pBBegin - 1, pBEnd);
int t2 = CalculateStringDistance(strA, pABegin, pAEnd-1, strB,pBBegin, pBEnd);
return minValue(t0, t1+1,t2+1,t3+1) ;
}
在递归的过程中,有些数据被重复计算了。DP的方法有从下到上的方法以及从上到下的备忘录方法。不再赘述
(http://blog.csdn.net/v_july_v/article/details/8701148)