问题描述

输入 原字符串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. Golang Gtk+3教程:GtkBuilder使用XML构建UI

    在这节我将介绍GtkBuilder,其使我们可以从一个描述界面的xml文件构建UI.而这个文件我们可以使用Glade生成,这会极大的方便我们编辑用户界面.这节我们会使用到这么一个XML文件,名字为Bu ...

  2. LDA线性判别分析原理及python应用(葡萄酒案例分析)

    目录 线性判别分析(LDA)数据降维及案例实战 一.LDA是什么 二.计算散布矩阵 三.线性判别式及特征选择 四.样本数据降维投影 五.完整代码 结语 一.LDA是什么 LDA概念及与PCA区别 LD ...

  3. linux手动安装python

    前提:你的linux服务器必须有gcc编译器,gcc查看方法:linux命令行>gcc -v 如果返回版本信息证明已经安装, 如果找不到命令,跳到这篇手动安装gcc >>> l ...

  4. 非确定性有穷状态决策自动机练习题Vol.2 C. 奇袭

    非确定性有穷状态决策自动机练习题Vol.2 C. 奇袭 题目描述 由于各种原因,桐人现在被困在\(Under World\)(以下简称\(UW\))中,而\(UW\)马上 要迎来最终的压力测试--魔界 ...

  5. Alpha阶段项目复审(鸽牌开发小分队)

    团队:鸽牌开发专业小分队 项目:必备记 集合帖:集合帖 项目复审: 团队名字 项目链接 优点 缺点和bug报告 最终名次 歪瑞古德小队 海岛漂流 1.功能齐全,上手简单2.界面简洁美观3.想法新颖,可 ...

  6. Reliable Federated Learning for Mobile Networks

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! 以下是对本文关键部分的摘抄翻译,详情请参见原文. arXiv: 1910.06837v1 [cs.CR] 14 Oct 2019 Abst ...

  7. Leetcode 24. Swap Nodes in Pairs(详细图解一看就会)

    题目内容 Given a linked list, swap every two adjacent nodes and return its head. You may not modify the ...

  8. 微信商户H5支付申请不通过被驳回解法,拒绝提示:网站有不实内容或不安全信息

    H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付.主要用于触屏版的手机浏览器请求微信支付的场景.可以方便从外部浏览器唤起 ...

  9. JavaSE基础--part1

    Java特性和优势 简单.面向对象.可移植性.高性能.分布式.动态性.多线程.安全性.健壮性 Java的三大版本 JavaSE 标准版(应用于桌面程序,控制台开发) JavaME 嵌入式开发(手机,小 ...

  10. Spring整合WebSocket

    WebSocket,干什么用的?我们有了HTTP,为什么还要用WebSocket?很多同学都会有这样的疑问.我们先来看一个场景,大家的手机里都有微信,在微信中,只要有新的消息,这个联系人的前面就会有一 ...