问题描述

输入 原字符串StrOrg,目标字符串StrTarget,插入、删除、替换的编辑代价ic,dc,rc。输出将原字符串编辑成目标字符串的最小代价。

解题思路

状态表示

dp[i][j]表示把strOrg[0:i]编辑成strTarget[0:j]的最小代价。

状态转移方程

从以下三种状态的取最小即可:

  • 删除:dp[i][j]=dp[i-1][j]+dc。原串删除最后一个元素,再转移到目标串
  • 插入:dp[i][j]=dp[i][j-1]+ic。原串变为目标元素删除最后一个元素,再插入最后一个元素。
  • 替换:dp[i][j]=dp[i-1][j-1]+rc。由原串除最后一个元素变为目标串除最后一个元素,再替换最后一个元素(特别地,若两串最后一个元素相等,则省去rc)

对空间进行压缩,空间复杂度压缩至O(min(M,N))

使用一维数组,由于dp[i][j]既依赖于dp[i][j-1]又依赖于dp[i-1][j-1],所以要有一个临时变量pre存dp[i-1][j-1].

注意

  • 注意对第一行和第一列的初始化。
  • 注意dp[i][j]表示的是不含strOri[i]和strTatget[j]元素的串,因为初始化第0行第0列的时候都表示的是空串。因此,开数组时也要多开一个位置。
  • 为了空间复杂度是两串长度的较短值:设置长串和短串,保证列数为短串的长度+1,如果目标串比原串长,则在换一下ic和+dc操作的代价值。

代码1(空间复杂度O(N)版,其中N为目标串长度)

import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner in=new Scanner(System.in);
while(in.hasNext()) {
String strOri=in.next();
String strTarget=in.next();
int ic=in.nextInt();
int dc=in.nextInt();
int rc=in.nextInt();
int editDis=getMinEditDis(strOri,strTarget,ic,dc,rc);
System.out.println(editDis);
}
} public static int getMinEditDis(String strOri,String strTarget,int ic,int dc,int rc){
int rows=strOri.length()+1;
int cols=strTarget.length()+1;
int dp[]=new int[cols]; for(int j=0;j<cols;++j) {
dp[j]=ic*j;//初始化第一行
} for(int i=1;i<rows;++i) {
int pre=dp[0];//pre记录dp[i-1][j-1]
dp[0]=dc*i;//初始化第一列
for(int j=1;j<cols;++j) {
int ansTemp;
if(strOri.charAt(i-1)==strTarget.charAt(j-1)) {//
ansTemp=pre;
}
else {
ansTemp=pre+rc;
}
int temp=dp[j];
dp[j]=getMin(ansTemp,dp[j]+dc,dp[j-1]+ic);//状态转移
pre=temp;//更新pre
}
}
return dp[cols-1];
} public static int getMin(int... vals) {
int min=Integer.MAX_VALUE;
for(int val:vals) {
if(val<min) {
min=val;
}
}
return min;
}
}

代码2(空间复杂度O(min(M,N))版)

import java.util.Scanner;

public class Main {
public static void main(String args[]) {
Scanner in=new Scanner(System.in);
while(in.hasNext()) {
String strOri=in.next();
String strTarget=in.next();
int ic=in.nextInt();
int dc=in.nextInt();
int rc=in.nextInt();
int editDis=getMinEditDis(strOri,strTarget,ic,dc,rc);
System.out.println(editDis);
}
} public static int getMinEditDis(String strOri,String strTarget,int ic,int dc,int rc){
String longs=strOri.length()>=strTarget.length()?strOri:strTarget;
String shorts=strOri.length()<strTarget.length()?strOri:strTarget;
int dp[]=new int[shorts.length()+1]; if(strOri.length()<strOri.length()) {
int temp=ic;
ic=dc;
dc=temp;
} for(int j=0;j<shorts.length()+1;++j) {
dp[j]=ic*j;//初始化第一行
} for(int i=1;i<longs.length()+1;++i) {
int pre=dp[0];//pre记录dp[i-1][j-1]
dp[0]=dc*i;//初始化第一列
for(int j=1;j<shorts.length()+1;++j) {
int ansTemp;
if(longs.charAt(i-1)==shorts.charAt(j-1)) {//
ansTemp=pre;
}
else {
ansTemp=pre+rc;
}
int temp=dp[j];
dp[j]=getMin(ansTemp,dp[j]+dc,dp[j-1]+ic);//状态转移
pre=temp;//更新pre
}
}
return dp[shorts.length()];
} public static int getMin(int... vals) {
int min=Integer.MAX_VALUE;
for(int val:vals) {
if(val<min) {
min=val;
}
}
return min;
}
}

[程序员代码面试指南]递归和动态规划-最小编辑代价(DP)的更多相关文章

  1. [程序员代码面试指南]递归和动态规划-数字字符串转换为字母组合的种数(DP)

    题意 给一个字符串,只由数字组成,若是'1'-'26',则认为可以转换为'a'-'z'对应的字母,问有多少种转换方法. 题解 状态转移很好想,注意dp多开一位,dp[0]为dp[2]的计算做准备.dp ...

  2. [程序员代码面试指南]递归和动态规划-排成一条线的纸牌博弈问题(DP)

    题目 给定一个整型数组arr,代表数值不同的纸牌排成一条线.玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿,但是每个玩家每次只能拿走最左或最右的纸牌,玩家A和玩家B都绝顶聪明.请返回最后获 ...

  3. [程序员代码面试指南]递归和动态规划-最长公共子串问题(DP,LCST)

    问题描述 如题. 例:输入两个字符串 str1="1AB234",str2="1234EF" ,应输出最长公共子串"234". 解题思路 状 ...

  4. [程序员代码面试指南]递归和动态规划-换钱的方法数(DP,完全背包)

    题目描述 给定arr,arr中所有的值都为正数且不重复.每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim,求组成aim的方法数. 解题思路 完全背包 和"求换钱的 ...

  5. [程序员代码面试指南]递归和动态规划-换钱的最少货币数(DP,完全背包)

    题目描述 给定arr,arr中所有的值都为正数且不重复.每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim,求组成aim的最少货币数. 解题思路 dp[i][j]表示只用第0 ...

  6. [程序员代码面试指南]递归和动态规划-机器人达到指定位置方法数(一维DP待做)(DP)

    题目描述 一行N个位置1到N,机器人初始位置M,机器人可以往左/右走(只能在位置范围内),规定机器人必须走K步,最终到位置P.输入这四个参数,输出机器人可以走的方法数. 解题思路 DP 方法一:时间复 ...

  7. 程序员代码面试指南 IT名企算法与数据结构题目最优解

    原文链接 这是一本程序员面试宝典!书中对IT名企代码面试各类题目的最优解进行了总结,并提供了相关代码实现.针对当前程序员面试缺乏权威题目汇总这一痛点,本书选取将近200道真实出现过的经典代码面试题,帮 ...

  8. 程序员代码面试指南:IT名企算法与数据结构题目最优解

      第1章栈和队列 1设计一个有getMin功能的栈(士★☆☆☆) 1由两个栈组成的队列(尉★★☆☆) 5如何仅用递归函数和栈操作逆序一个栈(尉★★☆☆) 8猫狗队列(士★☆☆☆)10用一个栈实现另一 ...

  9. [程序员代码面试指南]二叉树问题-找到二叉树中的最大搜索二叉树(树形dp)

    题意 给定一颗二叉树的头节点,已知所有节点的值都不一样,找到含有节点最多的搜索二叉子树,并返回这个树的头节点. 题解 在后序遍历过程中实现. 求解步骤按树形dp中所列步骤.可能性三种:左子树最大.右子 ...

随机推荐

  1. C++最好的图形库是什么?

    本文字数:1660,阅读时长大约:15分钟 世界上的GUI库多如牛毛,有的开源,有的收费,有的可以做手机app开发,有的可以做桌面应用,有的只能用在某个系统,有的支持跨平台.基于不同的编程语言,人们又 ...

  2. 因网络时代与云端应用而生的AGPL-3.0授权条款

    ​ 此篇文章转载自:因應網路時代與雲端應用而生的 AGPL-3.0 授權條款 如你所见,原文为繁体,我将其转为简体并将"网路"替换为"网络",方便阅读.并未修改 ...

  3. Spring Boot 教程 - 文件上传下载

    在日常的开发工作中,基本上每个项目都会有各种文件的上传和下载,大多数文件都是excel文件,操作excel的JavaAPI我用的是apache的POI进行操作的,POI我之后会专门讲到.此次我们不讲如 ...

  4. html表格、表单

    知识点一:表格 1.表格标签  table 2.表格的组成  行 tr  单元格  td 3.建立表格步骤 1.建立表格, 2.判断行数和列数 3.用行去包含单元格 4.在每个单元格中去添加内容 4. ...

  5. sql server 查询表字段的说明备注信息

    SELECT 表名 = case when a.colorder= then d.name else '' end, 表说明 = case when a.colorder= then isnull(f ...

  6. python 09 数据包 异常处理

    pickle模块操作文件 pickle.dump(obj, file[, protocol]) 序列化对象,并将结果数据流写入到文件对象中.参数protocol是序列化模式,默认值为0,表示以文本的形 ...

  7. vant官网无法打开,这里教你解决

    是否大家和我一样,vant-weapp官网突然打不开了   像这样: 但我发现在码云上有一个国内的版本 https://vant-contrib.gitee.io/vant/#/zh-CN/home, ...

  8. 5 个 Git 工作流,改善你的开发流程

    原文地址:5 Git workflows you can use to deliver better code and improve your development process 原文作者:Vi ...

  9. 牛客网PAT练兵场-D进制的A+B

    题解:大多数做法是利用循环相除,取余.我是将将A+B传入f函数,利用递归实现D进制的输出 题目地址:https://www.nowcoder.com/questionTerminal/a2063993 ...

  10. Linux教学资源服务器构建

    1. 需求分析 1.1 课题简介 随着计算机互联网的迅速发展,大多数学校已经实现教学的信息化,从传统的黑板教学方式转变为现阶段的多媒体教学,教学的资源,素材课件,甚至学生的作业也都实现数字化,为了实现 ...