最小编辑代价

目录

算法运用场景:

题目:

输入描述:

输出描述:

示例1

输入

输出

示例2

输入

输出

示例3

输入

输出

备注:

思路分析:

优化:

样例推导:

二维矩阵:

空间压缩:

代码展示:

二维矩阵:

空间压缩:


算法运用场景:

字符串之间最小距离是非常经典的题目,运用也非常广泛

比如在搜索中,输入:“数组的输出格式” 结果中:“字符数组输出格式”,“数组的输入输出”,

结果与我们搜索的内容虽然不一样,但是字符串距离却很小(相似)

题目:

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

输入描述:

输出三行,第一行和第二行均为一行字符串,分别表示两个字符串str1,str2。。第三行为三个正整数,代表ic,dc和rc。(1<=ic<=10000、1<=dc<=10000、1<=rc<=10000)

输出描述:

输出一个整数,表示编辑的最小代价。

示例1

输入

abc adc 5 3 2

输出

2

示例2

输入

abc adc 5 3 100

输出

8

示例3

输入

abc abc 5 3 2

输出

0

备注:

时间复杂度O(N*M),空间复杂度O(N)。(n,m代表两个字符串长度)

思路分析:

  1. 创建一个dp数组,dp[i][j]表示str1[0...i-1]组成的子串与str2[0...j-1]组成的子串的最优解
    1. 即长度为i的str1转换成长度为j的str2所需的最小代价
  2. 初始化:
    1. 首行:str1长度为0即空串。所以str1转换成str2必须用insert,即dp[0][j] = ic * j;
    2. 首列:str2长度为0即空串。所以str1转换成str2必须用delete,即dp[i][0] = dc * j;
  3. 其余点:
    1. str1[0...i-2]转换成str2[0...j-2]的代价 加上 将str1[i-1]转换成str[j-1]
      1. 若str1[i-1] = str2[j-1] 则dp[i-1][j-1] + rc*0;(最后一个元素相等不需要replace)
      2. 若str1[i-1] != str[j-1] 则dp[i-1][j-1] +rc*1;
    2. str1[0...i-2]转换成str2[0...j-1]的代价 加上 删去str1[i-1]的代价
      1. 即dp[i-1][j] +dc;
    3. str[0...i-1]的转换成str2[0...j-2]的代价 加上 在str1的末尾添加str2[j-1]的代价
      1. 即dp[i][j-1] +ic;
    4. 在以上三种可能性中取最小值
  4. 结果:
    1. dp[n][m]即为结果

优化:

题目要求空间复杂度为O(N) ,考虑用空间压缩的技巧

每个dp都只依赖与 左边,上面,与左上。所以用一个一维数组不断更新即可以实现

样例推导:

二维矩阵:

空间压缩:

代码展示:

二维矩阵:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main{
    private static boolean DEBUG = false;
    public static void main(String[] args)throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String str1 = reader.readLine();
        String str2 = reader.readLine();
        String[] idr = reader.readLine().split(" ");
        int ic = Integer.parseInt(idr[0]);
        int dc = Integer.parseInt(idr[1]);
        int rc = Integer.parseInt(idr[2]);
        
        int n = str1.length();
        int m = str2.length();
        int dp[][] = new int[n+1][m+1];
        
        //初始化
        for(int j=0;j<=m;j++){//首行
            dp[0][j] = j * ic; 
        }
        for(int i=0;i<=n;i++){
            dp[i][0] = i * dc;
        }
        
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                int p1 = dp[i-1][j-1] + rc * (str1.charAt(i-1)==str2.charAt(j-1)?0:1);
                int p2 = dp[i-1][j] + dc;
                int p3 = dp[i][j-1] + ic;
                dp[i][j] = Math.min(p1,Math.min(p2,p3));
                if(DEBUG) System.out.print(dp[i][j] + " ");
            }
            if(DEBUG) System.out.println();
        }
        
        System.out.print(dp[n][m]);
    }
}

空间压缩:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main{
    private static boolean DEBUG = false;
    public static void main(String[] args)throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String str1 = reader.readLine();
        String str2 = reader.readLine();
        String[] idr = reader.readLine().split(" ");
        int ic = Integer.parseInt(idr[0]);
        int dc = Integer.parseInt(idr[1]);
        int rc = Integer.parseInt(idr[2]);
        
        int n = str1.length();
        int m = str2.length();
        int dp[] = new int[m+1];
        
        //初始化
        for(int j=0;j<=m;j++){//首行
            dp[j] = j * ic; 
        }
        
        int temp = 0;
        for(int i=1;i<=n;i++){
            
            temp = dp[0];
            dp[0] = i * dc;
            if(DEBUG) System.out.print(dp[0] + " ");
            for(int j=1;j<=m;j++){
                int p1 = temp + rc * (str1.charAt(i-1)==str2.charAt(j-1)?0:1);
                temp = dp[j];
                int p2 = dp[j] + dc;
                int p3 = dp[j-1] + ic;
                dp[j] = Math.min(p1,Math.min(p2,p3));
                if(DEBUG) System.out.print(dp[j] + " ");
            }
            if(DEBUG) System.out.println();
        }
        
        System.out.print(dp[m]);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值