Loading

最小编辑代价

最小编辑代价

题目:最小编辑代价

《程序员代码面试指南》第68题 P230 难度:校★★★☆

同样分为经典动态规划经典动态规划结合空间压缩两种方法。

经典动态规划方法:

同样建立二维动态规划表,大小为(M+1)×(N+1)的矩阵dpdp[i][j]的值代表str1[0..i-1]编辑成str2[0..j-1]的最小代价

dp矩阵每个位置的值计算如下(具体原理见书P231):

  1. dp[0][0]=0
  2. 第一列dp[i][0]=dc*i
  3. 第一行dp[0][j]=ic*j
  4. 其它位置dp[i][j],取以下四种可能的值中的最小值
    1. dc+dp[i-1][j]
    2. dp[i][j-1]+ic
    3. 如果str1[i-1]!=str2[j-1]dp[i-1][j-1]+rc
    4. 如果str1[i-1]==str2[j-1]dp[i-1][j-1]
public int minCost1(String str1, String str2, int ic, int dc, int rc) {
    if (str1 == null || str2 == null) {
        return 0;
    }
    char[] chs1 = str1.toCharArray();
    char[] chs2 = str2.toCharArray();
    int row = chs1.length + 1;
    int col = chs2.length + 1;
    int[][] dp = new int[row][col];
    for (int i = 1; i < row; i++) {
        dp[i][0] = dc * i;
    }
    for (int j = 1; j < col; j++) {
        dp[0][j] = ic * j;
    }
    for (int i = 1; i < row; i++) {
        for (int j = 1; j < col; j++) {
            if (chs1[i - 1] == chs2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = dp[i - 1][j - 1] + rc;
            }
            dp[i][j] = Math.min(dp[i][j], dp[i][j - 1] + ic);
            dp[i][j] = Math.min(dp[i][j], dp[i - 1][j] + dc);
        }
    }
    return dp[row - 1][col - 1];
}

经典动态规划结合空间压缩方法:

与“矩阵的最小路径和”问题不同,本题dp[i][j]依赖dp[i-1][j]、dp[i][j-1]、dp[i-1][j-1]。还需要一个变量保存dp[j-1]没更新之前的值,即dp[i-1][j-1]

此外,选择str1和str2中长度较的一个作为对应的字符串,长度较的一个作为对应的字符串。如果str1做了对应的字符串,把插入代价ic和删除代价dc交换一下即可。

public int minCost2(String str1, String str2, int ic, int dc, int rc) {
    if (str1 == null || str2 == null) {
        return 0;
    }
    char[] chs1 = str1.toCharArray();
    char[] chs2 = str2.toCharArray();
    char[] longs = chs1.length >= chs2.length ? chs1 : chs2;
    char[] shorts = chs1.length < chs2.length ? chs1 : chs2;
    if (chs1.length < chs2.length) { // str2较长就交换ic和dc的值
        int tmp = ic;
        ic = dc;
        dc = tmp;
    }
    int[] dp = new int[shorts.length + 1];
    for (int i = 1; i <= shorts.length; i++) {
        dp[i] = ic * i;
    }
    for (int i = 1; i <= longs.length; i++) {
        int pre = dp[0]; // pre代表左上角的值ֵ
        dp[0] = dc * i;
        for (int j = 1; j <= shorts.length; j++) {
            int tmp = dp[j]; // dp[j]没更新前先保存下来
            if (longs[i - 1] == shorts[j - 1]) {
                dp[j] = pre;
            } else {
                dp[j] = pre + rc;
            }
            dp[j] = Math.min(dp[j], dp[j - 1] + ic);
            dp[j] = Math.min(dp[j], tmp + dc);
            pre = tmp; // pre变成dp[j]没更新前的值
        }
    }
    return dp[shorts.length];
}
posted @ 2022-03-23 19:47  幻梦翱翔  阅读(50)  评论(0)    收藏  举报