最小编辑代价:给定两个字符串str1和str2,再给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,请输出将str1编辑成str2的最小代价。

  • 较难的动态规划题目(主要要着眼于三个基本操作带来的操作):
  • 如果选择将str1的前i个字符转换为str2的前j个字符则需要分类讨论->dp[i]j
  • 如果str1[i] == str2[j]->则只需要将前i-1个字符转换为前j-1个字符即可,最后一个字符不动:dp[i][j] = dp[i-1][j-1]
  • 如果str1[i] != str2[j]->分三类操作:
  • 1.插入:将i个字符串转变为前j-1个字符串在插入第j个字符->dp[i][j-1]+ic
  • 2.删除:将i-1个字符串转换为前j个字符串删除第i个字符->dp[i-1][j]+id
  • 3.替换:将i-1个字符串转换为前j-1个字符串替换掉第i个字符为第j个字符->dp[i-1][j-1]+rc
  • 取最小的即可

public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
        // write code here
        public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
        // write code here
        int m = str1.length();
        int n = str2.length();
        //初始化dp[0][i]与dp[i][0]
        int[][] dp = new int[m+1][n+1];
        for(int i = 1;i <= m;i++){
            dp[i][0] = i*dc;
        }
        for(int i = 1;i <= n;i++){
            dp[0][i] = i*ic;
        }
        //开始遍历
        for(int i = 1;i <= m;i++){
            char c1 = str1.charAt(i-1);
            for(int j = 1;j <= n;j++){
                char c2 = str2.charAt(j-1);
                if(c1 == c2){
                    dp[i][j] = dp[i-1][j-1];
                }else{
                    //分类讨论,找到最小代价
                    int insert = dp[i][j-1] + ic;
                    int delete = dp[i-1][j] + dc;
                    int replace = dp[i-1][j-1] + rc;
                    dp[i][j] = Math.min(replace,Math.min(delete,insert));
                }
            }
        }
        return dp[m][n];
    }

动态规划(优化空间):因为根据未优化版本可得知,求解dp[i][j]只需要直到dp[i-1][j-1],dp[i][j-1],dp[i-1][j]

  • 不需要之后的数据,则可轻易得知,我们可以将其化为一维数组dp[n+1]的动态数组
  • 首先需要初始化dp[0][i]->先给dp赋值完成
  • 使用一个prev存储dp[i-1][j-1],每当读取当前dp[i]时,将其用一个temp存储下来,当做当前的dp[i-1][j]以及下一个的dp[i-1][j-1]即可

public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
        // write code here
        int m = str1.length();
        int n = str2.length();
        //初始化一位动态数组
        int[] dp = new int[n+1];
        //初始化dp[0][i]
        for(int i = 1;i <= n;i++){
            dp[i] = i * ic;
        }
        //开始遍历
        for(int i = 1;i <= m;i++){
            char c1 = str1.charAt(i-1);
            int prev = dp[0];
            dp[0] = i * dc;
            for(int j = 1;j <= n;j++){
                char c2 = str2.charAt(j-1);
                //获取dp[i-1][j]
                int temp = dp[j];
                if(c1 == c2){
                    dp[j] = prev;
                }else{
                    int insert = dp[j-1] + ic;
                    int delete = temp + dc;
                    int replace = prev + rc;
                    dp[j] = Math.min(insert, Math.min(delete, replace));
                }
                //更新dp[i-1][j-1]的局部变量
                prev = temp;
            }
        }
        return dp[n];
    }