[Leedcode][JAVA][第72题][动态规划]

【问题描述】 [72. 编辑距离]

给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。你可以对一个单词进行如下三种操作:插入一个字符
删除一个字符
替换一个字符示例 1:输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

【解答思路】

1.动态规划

第 1 步:定义状态
状态:dp[i][j] 表示将 word1[0, i) 转换成为 word2[0, j) 的方案数。

思考状态的方法:1、题目问什么就将什么定义为状态;2、「状态转移方程」怎么好推导,就怎么定义状态;3、根据经验和问题的特点(只有多做题了)。

说明:由于要考虑空字符,这里的下标 i 不包括 word[i],同理下标 j 不包括 word[j],从行数和列数多设置一行、一列也可以来理解这一点,也就是状态的下标 i 和 j 和字符的下标 i、j 有一个位置的偏差。

第 2 步:思考状态转移方程
状态转移方程通常是在做分类讨论,而分类讨论的过程,常常利用了这个问题的「最优子结构」。

情况 1:word1[i] == word2[j]
如果 word1[i] == word2[j] 成立,则将 word1[0, i) 转换成为 word2[0, j) 的方案数就等于 将 word1[0, i - 1) 转换成为 word2[0, j - 1) 的方案数,即:

dp[i + 1][j + 1] = dp[i][j];
注意:这种情况,方案数最少,后面三种情况可以不用讨论,在这里暂时忽略。

情况 2:word1[i] != word2[j]
如果 word1[i] != word2[j] ,则将 word1[0, i) 转换成为 word2[0, j) 的方案数就等于下面 3 种情况的最少操作数(「最优子结构」):

考虑修改 word1[i] 成为 word2[j];
此时 dp[i + 1][j + 1] = dp[i][j] + 1,这里的 1 代表了将 word1[i] 替换成为 word2[j] 这一步操作。

考虑将 word1[0, i] 的最后一个字符删除;
此时 word1[0, i - 1] 到 word2[0, j] 的最少操作数 + 1+1,就是这种方案数的最少操作数,即: dp[i + 1][j + 1] = dp[i][j + 1] + 1,这里的 1 代表了 word1[0, i] 的最后一个字符删除这一步操作。

考虑将 word1[0, i] 的末尾添加一个字符使得 word1[i + 1] == word2[j];
此时考虑方案的时候,由于 word1[i + 1] == word2[j],状态转移就不应该考虑 word2[j],因此 word1[0, i] 到 word2[0, j - 1] 的最少操作数 + 1+1,就是这种方案数的最少操作数,即: dp[i + 1][j + 1] = dp[i + 1][j] + 1,这里的 1 代表了将 word1[0, i] 的末尾添加一个字符使得 word1[i + 1] == word2[j]。(注意:可以考虑一下为什么得先讨论 word1[i] == word2[j] 的情况。)

在这 3 种操作中取最小值。

dp[i + 1][j + 1] = min(dp[i][j], dp[i][j + 1], dp[i + 1][j]) + 1

第 3 步:初始化
从一个字符串变成空字符串,非空字符串的长度就是编辑距离;
以下代码其实就是在填表格的第 00 行、第 00 列。

for (int i = 0; i <= len1; i++) {dp[i][0] = i;
}for (int j = 0; j <= len2; j++) {dp[0][j] = j;
}

第 4 步: 思考输出
输出:dp[len1][len2] 符合语义,即 word1[0, len) 转换成 word2[0, len2) 的最小操作数。(这里 ) 表示开区间。)

第 5 步: 思考状态压缩
我们看一下「状态转移方程」:

  • 如果末尾字符相等,就「抄」左上角单元格的值;
  • 如果末尾字符不相等,就从「正上方」、「左边」、「左上角」三个单元格的值中选出最小的 + 1。
    因此,初看可以使用「滚动数组」,更极端一点,用 2 \times 22×2 表格就可以完成操作。但是真正去做「状态压缩」的时候,由于初始化的原因,发现没有那么容易,在这里不做「状态压缩」。(事实上可以压缩,但是只要是压缩状态,必然给编码造成一定困难,并且破坏代码可读性,根据情况做吧,个人觉得在空间紧张的情况下必须压缩空间,其余不必。)

手填

时间复杂度:O(N^2) 空间复杂度:O(N)

import java.util.Arrays;public class Solution {public int minDistance(String word1, String word2) {// 由于 word1.charAt(i) 操作会去检查下标是否越界,因此// 在 Java 里,将字符串转换成字符数组是常见额操作char[] word1Array = word1.toCharArray();char[] word2Array = word2.toCharArray();int len1 = word1Array.length;int len2 = word2Array.length;// 多开一行一列是为了保存边界条件,即字符长度为 0 的情况,这一点在字符串的动态规划问题中比较常见int[][] dp = new int[len1 + 1][len2 + 1];// 初始化:当 word 2 长度为 0 时,将 word1 的全部删除for (int i = 1; i <= len1; i++) {dp[i][0] = i;}// 当 word1 长度为 0 时,就插入所有 word2 的字符for (int j = 1; j <= len2; j++) {dp[0][j] = j;}// 注意:填写 dp 数组的时候,由于初始化多设置了一行一列,横、纵坐标有个偏移for (int i = 0; i < len1; i++) {for (int j = 0; j < len2; j++) {// 这是最佳情况if (word1Array[i] == word2Array[j]) {dp[i + 1][j + 1] = dp[i][j];continue;}// 否则在以下三种情况中选出步骤最少的,这是「动态规划」的「最优子结构」// 1、在下标 i 处插入一个字符int insert = dp[i + 1][j] + 1;// 2、替换一个字符int replace = dp[i][j] + 1;// 3、删除一个字符int delete = dp[i][j + 1] + 1;dp[i + 1][j + 1] = Math.min(Math.min(insert, replace), delete);}}// 打印状态表格进行调试
//        for (int i = 0; i <=len1; i++) {
//            System.out.println(Arrays.toString(dp[i]));
//        }return dp[len1][len2];}public static void main(String[] args) {String word1 = "horse";String word2 = "ros";Solution solution = new Solution();int res = solution.minDistance(word1, word2);System.out.println(res);}
}作者:liweiwei1419
链接:https://leetcode-cn.com/problems/edit-distance/solution/dong-tai-gui-hua-java-by-liweiwei1419/

【总结】

  1. 动态规划
  • 「自底向上」去考虑一个问题
    思考的时候可以先将大区间拆分成小区间,求解的时候由小区间的解得到大区间的解。
  1. 「动态规划」求解的问题的三个特征:
  • 重叠子问题
  • 最优子结构
  • 无后效性
  1. 动态规划解题步骤
    第 1 步:定义状态
    第 2 步:思考状态转移方程
    第 3 步:初始化
    第 4 步: 思考输出
    第 5 步: 思考状态压缩

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/426040.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker操作笔记(二)容器

容器 一、启动容器 启动一个容器有两种方式&#xff1a; 1.基于镜像新键并启动一个容器&#xff1a; 所需要的主要命令为docker run docker run ubuntu:18.04 /bin/echo "hello" #启动一个bash终端 docker run -t -i ubuntu:18.04 /bin/bash 其中&#xff0c;-t 选项…

java学习(145):file常用方法2

import java.io.File; import java.io.IOException; import java.net.URI; import java.util.List;//文件管理类 public class FileManager {public static File createFileAction(URI uri){//使用URI做出参数创建对象if(uri!null)return new File( uri );return null;}//dir文…

java uipath_10.3 UiPath如何调用Java

调用Java方法(Invoke Java Method)的介绍从Java Scope中的.jar加载的方法中调用指定的Java方法。并结果存储在变量中二、Invoke Java Method 在UiPath中的使用打开设计器, 在设计库中新建一个Sequence&#xff0c;为序列命名及设置Sequence存放的路径, 在Activities中搜索Java …

Mybatis注解开发之@Results

写在前面&#xff1a;在使用mybatis注解开发的时候&#xff0c;数据库返回的结果集和实体类字段不对应&#xff0c;我们就需要手动指定映射关系&#xff1b; 一种是使用在xml文件中指定resultMap&#xff0c;指定id&#xff0c;下面需要的直接引用id就可以&#xff1b; 另一种在…

java学习(146):file常用方法3

import java.io.File; import java.io.IOException; import java.net.URI; import java.util.List;//文件管理类 public class FileManager {public static File createFileAction(URI uri){//使用URI做出参数创建对象if(uri!null)return new File( uri );return null;}//dir文…

[算法][二分查找][排除法]

最基本的二分查找算法 「搜索区间」是 [left, right] nums[mid] target 时可以立即返回 int binary_search(int[] nums, int target) {int left 0, right nums.length - 1; while(left < right) {int mid left (right - left) / 2;//防止大数溢出if (nums[mid] < t…

php getcount_PHP中关键字interface和implements详解

搜索热词PHP 类是单继承&#xff0c;也就是不支持多继承&#xff0c;当一个类需要多个类的功能时&#xff0c;继承就无能为力了&#xff0c;为此 PHP 引入了类的接口技术。如果一个抽象类里面的所有方法都是抽象方法&#xff0c;且没有声明变量&#xff0c;而且接口里面所有的成…

python操作文件

一、python中对文件、文件夹操作时经常用到的os模块和shutil模块常用方法。1.得到当前工作目录&#xff0c;即当前Python脚本工作的目录路径: os.getcwd()2.返回指定目录下的所有文件和目录名:os.listdir()3.函数用来删除一个文件:os.remove()4.删除多个目录&#xff1a;os.rem…

java学习(147):字节输入流

//读取二进制文件&#xff0c;字节输入流 import java.io.*;public class FileMana {public static void readBitFile(String filename){//1建立目标要读取的文件对象File filenew File( filename );//2基于目标对象建立输入流InputStream innull;if(file.exists()){//如果文件…

[Leedcode][JAVA][面试题 01.07][找规律][旋转数组]

【问题描述】 [面试题 01.07. 旋转矩阵] 示例 1:给定 matrix [[1,2,3],[4,5,6],[7,8,9] ],原地旋转输入矩阵&#xff0c;使其变为: [[7,4,1],[8,5,2],[9,6,3] ]给你一幅由 N N 矩阵表示的图像&#xff0c;其中每个像素的大小为 4 字节。请你设计一种算法&#xff0c;将图像…

php pmp是什么,pmp 总时差 自由时差 说明 和计算

pmp 总时差 自由时差 说明 和计算总浮动时间LS-ES 或 LF-EF总浮动时间是针对同一个活动来说的自由浮动时间是针对两个紧邻活动来说的自由活动时间紧后活动的最早开始时间-紧前活动的最晚结束时间总时差同一个活动的LS-ESLS:最晚开始&#xff0c;ES&#xff1a;最早开始eg:(以下…

java学习(148):三个参数的输入流

//3个参数读取二进制文件 import java.io.*;public class FileManage {public static void readBitFile(String filename){//1建立目标要读取的文件对象File filenew File( filename );//2基于目标对象建立输入流InputStream innull;if(file.exists()){//如果文件存在&#xff…

[剑指offer][JAVA][面试题第13题][机器人的运动][DFS][BFS]

【问题描述】 [中等] 地上有一个m行n列的方格&#xff0c;从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动&#xff0c;它每次可以向左、右、上、下移动一格&#xff08;不能移动到方格外&#xff09;&#xff0c;也不能进入行坐标和列坐标的数位之和…

ios php rsa,RSA 加密 iOS

在iOS端使用RSA加密的记录一、需求&#xff1a;SDK开发&#xff0c;使用RSA加密和后台进行数据交互&#xff0c;后台是PHP要求&#xff1a;1、post请求&#xff0c;客户端放公钥&#xff0c;私钥放后台2、发送数据&#xff1a;客户端的json数据—>RSA加密数据—>base64编…

java学习(149):字符输入流

import javax.imageio.IIOException; import java.io.*; import java.util.Date;//字符输入流 public class FileManagerChar {public static void readCharFile(File file){FileReader fileReadernull;//文本输入流if(file.exists()){try {fileReader new FileReader( file )…

如何伪造IP(转)

要明白伪装IP的原理&#xff0c;首先要回顾一下TCP的三次握手。 总所周知在链接初始化的阶段&#xff0c; 需要一次三次握手来建立链接&#xff0c; 之后客户端和服务端会依据初始的这个IP地址来通信。 从这个角度上来说&#xff0c; 想真正的伪装一个IP地址是不可能的。 因为即…

java三年,Java开发三年,你不得不了解的JVM(一)

基本概念&#xff1a;JVM 是可运行 Java 代码的假想计算机 &#xff0c;包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收&#xff0c;堆 和 一个存储方法域。JVM 是运行在操作系统之上的&#xff0c;它与硬件没有直接的交互。运行过程&#xff1a;我们都知道Java源文件…

[Leedcode][JAVA][第22题括号生成][DFS][BFS][动态规划]

【问题描述】22. 括号生成 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例&#xff1a;输入&#xff1a;n 3 输出&#xff1a;["((()))","(()())","(())()","()(…

java学习(150):文本缓冲流

import javax.imageio.IIOException; import java.io.*; import java.util.Date;//字符输入流 public class FileManagerChar {public static void readCharFile(File file){FileReader fileReadernull;//文本输入流if(file.exists()){try {fileReader new FileReader( file )…

微信小程序初始化 operateWXData:fail invalid scope

初学者开发微信小程序&#xff0c;可以使用云开发来进行微信小程序的开发。 第一次使用开发工具遇到的问题 解决方案&#xff1a;1、找到云开发 2、点击开通&#xff0c;选择合适自己的开发环境&#xff1b; 3、完成后&#xff0c;返回开发工具界面点击项目第一个节点“cloudfu…