#include <stdio.h> /** * 对于序列S和T,它们之间距离定义为:对二者其一进行几次以下的操作 * (1)删去一个字符;(2)插入一个字符;(3)改变一个字符。每进行一次操作,计数增加1。 * 将S和T变为同一个字符串的最小计数即为它们的距离。给出相应算法。 */ #define MIN(x,y) (x<y?x:y) #define INF 50000 #define SL 7 //字符串s的有效长度 #define TL 5 //字符串t的有效长度 static char s[SL+2] = " acbdepo"; static char t[TL+2] = " abcde"; /** * 我的思路如下 * 设子问题为:请求出字符串s的前i个字符组成的字符串与字符串t前j个字符组成的字符串 * 每次对其一进行以下其中一项操作: (1)删去一个字符;(2)插入一个字符;(3)改变一个字符。 * 每次操作后操作数+1,最终使两个字符串相等,求最小的操作数minSum * 找出边界:显然i=0时,minSum=j,因为i=0时,所需要的就是连续插入j次对应字符串t的字符, * 同理j=0时也一样 */ //递归 int solve_1(int i, int j){ if (i == 0) return j; if (j == 0) return i; //i和j大于0的情况 int cost = s[i] == t[j] ? 0 : 1; int del = solve_1(i-1, j) + 1; int add = solve_1(i, j-1) + 1; int upd = solve_1(i-1, j-1) + cost; return MIN(del, MIN(add, upd)); } //递归+记忆数组的dp static int memo[SL+1][TL+1]; int solve_2(int i, int j){ if (i == 0) return memo[i][j] = j; if (j == 0) return memo[i][j] = i; if (memo[i][j] < INF) return memo[i][j]; //i和j大于0的情况 int cost = s[i] == t[j] ? 0 : 1; int del = solve_2(i-1,j) + 1; int add = solve_2(i,j-1) + 1; int upd = solve_2(i-1,j-1) + cost; return memo[i][j] = MIN(del, MIN(add, upd)); } //递推 static int dp[SL+1][TL+1]; int solve_3(){ for (int i = 0; i <= SL; ++i) { dp[i][0] = i; } for (int j = 0; j <= TL; ++j) { dp[0][j] = j; } for (int i = 1; i <= SL; ++i) { for (int j = 1; j <= TL; ++j) { if (s[i] == t[j]) dp[i][j] = dp[i-1][j-1]; else{ int del = dp[i-1][j] + 1; int add = dp[i][j-1] + 1; int upd = dp[i-1][i-1] + 1; dp[i][j] = MIN(del, MIN(add, upd)); } } } return dp[SL][TL]; } int main() { printf("solve_1:%d\n", solve_1(SL, TL)); for (int i = 0; i <= SL; ++i) { for (int j = 0; j <= TL; ++j) { memo[i][j] = INF; } } printf("solve_2:%d\n", solve_2(SL, TL)); // for (int i = 0; i <= SL; ++i) { // for (int j = 0; j <= TL; ++j) { // printf("%d ",memo[i][j]); // } // printf("\n"); // } printf("solve_3:%d\n", solve_3()); return 0; }
运行结果:
solve_1:4
solve_2:4
solve_3:4