给定一个源串和目标串,能够对源串进行如下操作:
1. 在给定位置上插入一个字符
2. 替换任意字符
3. 删除任意字符
写一个程序,返回最小操作数,使得对源串进行这些操作后等于目标串,源串和目标串的长度都小于2000。
此题常见的思路是动态规划,假如令dp[i][j] 表示源串S[0…i] 和目标串T[0…j] 的最短编辑距离,其边界:dp[0][j] = j,dp[i][0] = i,那么我们可以得出状态转移方程:
}
接下来,咱们重点解释下上述3个式子的含义
上述的解释清晰规范,但为啥这样做呢?
换一个角度,其实就是字符串对齐的思路。例如把字符串“ALGORITHM”,变成“ALTRUISTIC”,那么把相关字符各自对齐后,如下图所示:
把图中上面的源串S[0…i] = “ALGORITHM”编辑成下面的目标串T[0…j] = “ALTRUISTIC”,我们枚举字符串S和T最后一个字符s[i]、t[j]对应四种情况:(字符-空白)(空白-字符)(字符-字符)(空白-空白)。
由于其中的(空白-空白)是多余的编辑操作。所以,事实上只存在以下3种情况:
综上,可以写出简单的DP状态方程:
//dp[i,j]表示表示源串S[0…i] 和目标串T[0…j] 的最短编辑距离 dp[i, j] = min { dp[i - 1, j] + 1, dp[i, j - 1] + 1, dp[i - 1, j - 1] + (s[i] == t[j] ? 0 : 1) } //分别表示:删除1个,添加1个,替换1个(相同就不用替换)。
#include <stdio.h> #include <stdlib.h> #include <string.h> #define myMin(a, b) (((a) < (b)) ? (a) : (b)) int dp[1001][1001]; int eidtDistance(char *pSource, char *pTarget) { int srcLen = strlen(pSource); int trgtLen = strlen(pTarget); int i, j; for (i = 0; i <=srcLen; ++i) dp[i][0] = i; for (j = 1; j <= trgtLen; ++j) dp[0][j] = j; for ( i = 1; i <= srcLen; ++i) for(j = 1; j <= trgtLen; ++j) { if (pSource[i - 1] == pTarget[j - 1]) dp[i][j] = dp[i-1][j-1]; else dp[i][j] = myMin(myMin(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1; } return dp[srcLen][trgtLen]; } int main(void) { char pSource[] = "ACB"; char pTarget[] = "ABCDEF"; int res; res = eidtDistance(pSource, pTarget); printf("%d\n", res); return 0; }
原文地址:http://blog.csdn.net/jjjcainiao/article/details/38844785