当前位置: 首页 > news >正文

代码随想录算法训练营第五十六天 | 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结

583. 两个字符串的删除操作

动规五部曲

1、确定dp数组(dp table)以及下标的含义

dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。

2、确定递推公式

当word1[i - 1] 与 word2[j - 1]相同的时候,dp[i][j] = dp[i - 1][j - 1];

当word1[i - 1] 与 word2[j - 1]不相同的时候,有三种情况:

情况一:删word1[i - 1],最少操作次数为dp[i - 1][j] + 1

情况二:删word2[j - 1],最少操作次数为dp[i][j - 1] + 1

情况三:同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2

当word1[i - 1] 与 word2[j - 1]不相同的时候,递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});

因为 dp[i][j - 1] + 1 = dp[i - 1][j - 1] + 2,所以递推公式可简化为:dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);

当 同时删word1[i - 1]和word2[j - 1],dp[i][j-1] 本来就不考虑 word2[j - 1]了,那么在删 word1[i - 1],就达到了两个元素都删除的效果,即 dp[i][j-1] + 1

3、dp数组如何初始化

从递推公式中,可以看出来,dp[i][0] 和 dp[0][j]是一定要初始化的。

dp[i][0]:word2为空字符串,以i-1为结尾的字符串word1要删除多少个元素,才能和word2相同呢,很明显dp[i][0] = i。

4、确定遍历顺序

从递推公式 dp[i][j] = min(dp[i - 1][j - 1] + 2, min(dp[i - 1][j], dp[i][j - 1]) + 1); 和dp[i][j] = dp[i - 1][j - 1]可以看出dp[i][j]都是根据左上方、正上方、正左方推出来的。

5、举例推导dp数组

以word1:"sea",word2:"eat"为例,推导dp数组状态图如下:

class Solution {
public:int minDistance(string word1, string word2) {vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1));for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;for (int i = 1; i <= word1.size(); i++) {for (int j = 1; j <= word2.size(); j++) {if (word1[i - 1] == word2[j - 1]) {dp[i][j] = dp[i - 1][j - 1];} else {dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);}}}return dp[word1.size()][word2.size()];}
};

思路二

只要求出两个字符串的最长公共子序列长度即可,那么除了最长公共子序列之外的字符都是必须删除的,最后用两个字符串的总长度减去两个最长公共子序列的长度就是删除的最少步数。

class Solution {
public:int minDistance(string word1, string word2) {vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));for (int i = 1; i <= word1.size(); i++) {for (int j = 1; j <= word2.size(); j++) {if (word1[i - 1] == word2[j - 1]) {dp[i][j] = dp[i - 1][j - 1] + 1;} else {dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);}}}return word1.size() + word2.size() - dp[word1.size()][word2.size()] * 2;}
};

72. 编辑距离

动规五部曲

1、确定dp数组(dp table)以及下标的含义

dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]

2、确定递推公式

在确定递推公式的时候,首先要考虑清楚编辑的几种操作,整理如下:

if (word1[i - 1] == word2[j - 1])不操作
if (word1[i - 1] != word2[j - 1])增删换

if (word1[i - 1] == word2[j - 1]) 那么说明不用任何编辑,dp[i][j] 就应该是 dp[i - 1][j - 1],即dp[i][j] = dp[i - 1][j - 1];

if (word1[i - 1] != word2[j - 1])

  • 操作一:word1删除一个元素,那么就是以下标i - 2为结尾的word1 与 j-1为结尾的word2的最近编辑距离 再加上一个操作。

dp[i][j] = dp[i - 1][j] + 1;

  • 操作二:word2删除一个元素,那么就是以下标i - 1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 再加上一个操作。

dp[i][j] = dp[i][j - 1] + 1;

word2添加一个元素,相当于word1删除一个元素,例如 word1 = "ad" ,word2 = "a"word1删除元素'd'word2添加一个元素'd',变成word1="a", word2="ad"

操作三:替换元素,word1替换word1[i - 1],使其与word2[j - 1]相同,此时不用增删加元素。

if (word1[i - 1] != word2[j - 1]) 时取最小的,即:dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;

3、dp数组如何初始化

dp[i][0] :以下标i-1为结尾的字符串word1,和空字符串word2,最近编辑距离为dp[i][0]。

那么dp[i][0]就应该是i,对word1里的元素全部做删除操作,即:dp[i][0] = i;

同理dp[0][j] = j;

4、确定遍历顺序

从如下四个递推公式:

  • dp[i][j] = dp[i - 1][j - 1]
  • dp[i][j] = dp[i - 1][j - 1] + 1
  • dp[i][j] = dp[i][j - 1] + 1
  • dp[i][j] = dp[i - 1][j] + 1

可以看出dp[i][j]是依赖左方,上方和左上方元素的,如图:

所以在dp矩阵中一定是从左到右从上到下去遍历。

 5、举例推导dp数组

以示例1为例,输入:word1 = "horse", word2 = "ros"为例,dp矩阵状态图如下:

class Solution {
public:int minDistance(string word1, string word2) {vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1));for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;for (int i = 1; i <= word1.size(); i++) {for (int j = 1; j <= word2.size(); j++) {if (word1[i - 1] == word2[j - 1]) {dp[i][j] = dp[i - 1][j - 1];} else {dp[i][j] = min(dp[i - 1][j], min(dp[i][j - 1], dp[i - 1][j - 1])) + 1;}}}return dp[word1.size()][word2.size()];}
};

 

编辑距离总结

编辑距离从判断子序列->判断子序列 ->不同的子序列 ->两个字符串的删除操作->编辑距离

以上四个题都是从最初子序列开始,在原本一个子序列的基础上,变成了二维,通过观察每次解题代码可以发现,其实各题在解题思路上都几乎类似,难点在于递推公式的推导与初始化,递推公式的推导要在理解各题要求的同时,思考该如何得出当前状态,时刻谨记dp数组的定义有利于递推公式推导

相关文章:

代码随想录算法训练营第五十六天 | 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结

583. 两个字符串的删除操作 动规五部曲 1、确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j]&#xff1a;以i-1为结尾的字符串word1&#xff0c;和以j-1位结尾的字符串word2&#xff0c;想要达到相等&#xff0c;所需要删除元素的最少次数。 2、确定递推…...

Sip协议

简介 SIP&#xff08;Session Initiation Protocol&#xff0c;会话初始协议&#xff09;是一个用于建立、更改和终止多媒体会话的应用 层控制协议&#xff0c;其中的会话可以是 IP 电话、多媒体会话或多媒体会议。SIP 是 IETF 多媒体数据和控 制体系结构的核心协议&#xff0…...

RandomAccessFile类 断点续传

文章目录学习链接RandomAccessFile构造方法实现的接口DataOutputDataInputAutoCloseable重要的方法多线程读写同一个文件&#xff08;多线程复制文件&#xff09;代码1代码2断点续传FileUtils学习链接 RandomAccessFile详解 Java IO——RandomAccessFile类详解 java多线程-断点…...

SpringCloud微服务技术栈的注册中心Eureka

文章目录SpringCloud微服务技术栈的注册中心Eureka简介Eureka特点操作步骤环境准备创建Eureka Server注册服务提供方调用服务消费方总结SpringCloud微服务技术栈的注册中心Eureka 简介 在微服务架构中&#xff0c;服务的数量庞大&#xff0c;而且每个服务可能会有多个实例。此…...

Unity最新热更新框架 hybridclr_addressable

GitHub:YMoonRiver/hybridclr_addressable: 开箱即用的商业游戏框架&#xff0c;集成了主流的开发工具。将主流的GameFramework修改&#xff0c;支持Addressable和AssetBundle&#xff0c;已完善打包工具和流程。 (github.com) # 新增GameFramework Addressables 开箱即用 # 新…...

【c语言】一维数组***特性、存储原理

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…...

[oeasy]python0133_[趣味拓展]好玩的unicode字符_另类字符_上下颠倒英文字符

另类字符 回忆上次内容 上次再次输出了大红心♥ 找到了红心对应的编码黑红梅方都对应有编码 原来的编码叫做 ascii️ \u这种新的编码方式叫unicode包括了 中日韩字符集等 各书写系统的字符集 除了这些常规字符之外 还有什么好玩的东西呢&#xff1f; 颠倒字符 这个网站可以…...

找凶手,定名次,字符串旋转,杨氏矩阵

1.找凶手问题&#xff1a; //题目名称&#xff1a; //猜凶手 //题目内容&#xff1a; //日本某地发生了一件谋杀案&#xff0c;警察通过排查确定凶手必为4个嫌疑犯的一个。 //以下为4个嫌疑犯的供词&#xff1a; //A说&#xff1a;不是我 //B说&#xff1a;是C //C说&#xff…...

Python 进阶指南(编程轻松进阶):十四、实践项目

原文&#xff1a;http://inventwithpython.com/beyond/chapter14.html 到目前为止&#xff0c;这本书已经教会了你编写可读的 Python 风格代码的技巧。让我们通过查看两个命令行游戏的源代码来实践这些技术&#xff1a;汉诺塔和四人一排。 这些项目很短&#xff0c;并且基于文…...

Redis的五种数据类型及应用场景

Redis是一个开源的key-value数据库。 五种数据类型 String&#xff0c;List&#xff0c; Set&#xff0c;SortedSet&#xff0c;Hash List类型可以存储多个String。 Set类型可以存储不同的String。 SortedSet可以存储String的排序。 Hash可以存储多个key-value对。 String …...

c++List的详细介绍

cList详细使用 write in front 作者&#xff1a; 不进大厂不改名 专栏&#xff1a; c 作者简介&#xff1a;大一学生 希望能向其他大佬和同学学习&#xff01; 本篇博客简介&#xff1a;本文主要讲述了一种新容器list的使用方法&#xff0c;相信你在学了后&#xff0c;能够加深…...

Heap堆的升序排序

在heap堆中&#xff0c;大根堆是一种特殊的堆&#xff0c;它满足下列性质&#xff1a;对于任意一个非叶子节点i&#xff0c;其左右子节点的值均小于等于它本身的值。 在大根堆中&#xff0c;堆顶元素永远是值最大的元素&#xff0c;所以将堆顶元素不断取出来&#xff0c;就相当…...

小程序开发收费价目表

小程序作为一种新兴应用形式&#xff0c;正在逐渐成为企业和个人推广、运营的重要手段。然而&#xff0c;小程序开发的价格因项目规模和复杂程度差异较大&#xff0c;令不少人望而却步。本文将从小程序开发的相关因素入手&#xff0c;探讨小程序开发的价格范围和算法。 一、小…...

Dubbo服务暴露步骤详解

文章目录Dubbo服务暴露步骤详解背景介绍理论知识讲解什么是服务暴露&#xff1f;Dubbo 服务暴露的基本原理操作步骤具体实现环境准备实现服务接口实现服务提供者配置 Dubbo 服务提供者启动服务提供者实现服务消费者配置 Dubbo 服务消费者测试总结Dubbo服务暴露步骤详解 背景介…...

第十四届蓝桥杯编程题部分代码题解

C. 冶炼金属 最大值就是取 a/ba / ba/b 的最小值&#xff0c;最小值就是二分找到满足 mid∗(bi1)≥aimid * (b_i 1) ≥ a_imid∗(bi​1)≥ai​ 的最小值 #include<bits/stdc.h> #define int long long #define x first #define y second using namespace std;void sol…...

统一结果封装异常处理

统一结果封装&异常处理2&#xff0c;统一结果封装2.1 表现层与前端数据传输协议定义2.2 表现层与前端数据传输协议实现2.2.1 环境准备2.2.2 结果封装步骤1:创建Result类步骤2:定义返回码Code类步骤3:修改Controller类的返回值步骤4:启动服务测试3&#xff0c;统一异常处理3…...

数字藏品平台的发展趋势是什么?

1、数字藏品平台具体内容生产模式将在PGC&#xff08;专业生产制造具体内容&#xff09;方式向PUGC&#xff08;技术专业用户生产内容&#xff09;方式变化。 目前&#xff0c;中国热门的数字藏品平台都在PGC模式中持续发展的&#xff0c;而国外流行NFT平台则比较多选用UGC&am…...

Vue3对话框(Dialog)

Vue2对话框&#xff08;Dialog&#xff09; 可自定义设置以下属性&#xff1a; 标题&#xff08;title&#xff09;&#xff0c;类型&#xff1a;string | slot&#xff0c;默认 提示 内容&#xff08;content&#xff09;&#xff0c;类型&#xff1a;string | slot&#xf…...

【深度强化学习】(5) DDPG 模型解析,附Pytorch完整代码

大家好&#xff0c;今天和各位分享一下深度确定性策略梯度算法 (Deterministic Policy Gradient&#xff0c;DDPG)。并基于 OpenAI 的 gym 环境完成一个小游戏。完整代码在我的 GitHub 中获得&#xff1a; https://github.com/LiSir-HIT/Reinforcement-Learning/tree/main/Mod…...

unity,Color.Lerp函数

介绍 Color.Lerp函数是Unity引擎中的一个静态函数&#xff0c;用于在两个颜色值之间进行线性插值&#xff0c;从而实现颜色渐变效果 方法 Color.Lerp函数是Unity引擎中的一个静态函数&#xff0c;用于在两个颜色值之间进行线性插值&#xff0c;从而实现颜色渐变效果。该函数的…...

clj-kondo Hook系统完全指南:自定义宏和函数的智能分析

clj-kondo Hook系统完全指南&#xff1a;自定义宏和函数的智能分析 【免费下载链接】clj-kondo Static analyzer and linter for Clojure code that sparks joy 项目地址: https://gitcode.com/gh_mirrors/cl/clj-kondo clj-kondo 是一款为 Clojure 代码提供静态分析和 …...

避开IAP跳转的坑:深入STM32的bin文件,搞懂PC指针和中断向量表那点事

避开IAP跳转的坑&#xff1a;深入STM32的bin文件&#xff0c;搞懂PC指针和中断向量表那点事 在嵌入式开发中&#xff0c;IAP&#xff08;In-Application Programming&#xff09;功能是实现设备固件远程升级的关键技术。然而&#xff0c;许多工程师在实现Bootloader跳转到App时…...

C++/WinRT安全编程:Windows Runtime安全模型和最佳实践

C/WinRT安全编程&#xff1a;Windows Runtime安全模型和最佳实践 【免费下载链接】cppwinrt C/WinRT 项目地址: https://gitcode.com/gh_mirrors/cp/cppwinrt C/WinRT是Windows Runtime&#xff08;WinRT&#xff09;的现代C语言投影&#xff0c;它提供了类型安全的API访…...

Arm/Keil开发工具VC++运行库版本排查指南

1. 排查Arm/Keil工具依赖的VC运行库版本在Windows环境下使用Arm Development Studio、Keil MDK等开发工具时&#xff0c;经常需要确认其依赖的Microsoft Visual C Redistributable&#xff08;简称VC运行库&#xff09;版本。这不仅是软件兼容性检查的常规操作&#xff0c;更是…...

数据血缘是什么?怎么建设数据血缘?

今年跟十几个企业老板聊AI落地&#xff0c;发现大家都有一个共识&#xff1a;不上AI是等死&#xff0c;乱上AI是找死。为什么&#xff1f;因为AI这玩意儿就像顶级厨师&#xff0c;食材不新鲜、来历不明&#xff0c;做出来的菜照样能毒倒一片。这里的食材&#xff0c;就是数据。…...

智能体状态管理:会话、上下文与检查点

从一个“跑了三天三夜的Agent突然失忆”说起&#xff0c;聊聊状态管理的那些坑先给你讲一个让我头皮发麻的运维事故。 去年冬天&#xff0c;我们做了一个自动爬取竞品价格并生成调价建议的Agent。它跑得很好&#xff0c;连续工作了三天&#xff0c;完成了两万多件商品的价格监控…...

独立开发者如何利用 Taotoken 模型广场低成本试错选型

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 独立开发者如何利用 Taotoken 模型广场低成本试错选型 对于资源有限的独立开发者或小型团队而言&#xff0c;在产品开发初期选择合…...

AI 驱动多渠道网络钓鱼攻击演化与闭环防御体系研究

摘要 2026 年全球网络空间中&#xff0c;AI 技术全面渗透使网络钓鱼攻击呈现工业化、多渠道、高仿真、强隐蔽的演化趋势&#xff0c;攻击载体从传统邮件快速扩散至即时通讯、协作平台、二维码与短链接等多元场景&#xff0c;传统基于特征库与规则匹配的防御机制失效风险显著上升…...

写论文缺参考文献?教你一招最快的反向查文献

写文献综述、毕业论文、科研报告时&#xff0c;你是不是也常遇到这些难题&#xff1a;观点明明写得很清楚&#xff0c;却找不到权威文献支撑&#xff1b;文献综述凑不够篇幅&#xff0c;论据来源不充分&#xff1b;逐篇翻数据库筛选文献太耗时&#xff0c;引文格式排版还总出错…...

基于SpringBoot的共享汽车管理系统毕设源码

博主介绍&#xff1a;✌ 专注于Java,python,✌关注✌私信我✌具体的问题&#xff0c;我会尽力帮助你。一、研究目的本研究旨在构建一个基于Spring Boot与Vue框架的共享汽车管理系统以解决当前共享汽车行业在资源调度效率、用户服务体验以及数据安全等方面存在的核心问题。随着城…...