C++ day56 两个字符串的删除操作 编辑距离

news2025/1/21 12:06:20

题目1:583 两个字符串的删除操作

题目链接:两个字符串的删除操作

对题目的理解

返回使两个单词word1和word2相同的最少删除多少个元素,两个单词至少包含一个字母,且仅包含小写字母

思路1:这道题与昨天的不同子序列很相似,只是有一点不同,不同子序列是使用s字符串去匹配t字符串,而本题可以对word1进行删减得到word2,也可以用word2删减获得word1,经过一系列删除操作,最终两个单词相等就可以了。

思路2:本题其实就是求word1和word2达到最长公共子序列时,使用两个单词的长度之和减去最长公共子序列的长度的2倍。

动态规划(思路1)

动规五部曲

1)dp数组及下标i的含义

dp[i][j]:以i-1结尾的word1和以j-1结尾的word2达到word1和word2相同的最少操作次数

2)递推公式

还是考虑两种情况,当前子串word1结尾的字符与子串word2结尾的字符相等和不等的情况

i)结尾的字符相等,即word1[i-1]==word2[j-1],因为已经相等了,这两个字符就不会改变操作的次数,那么此时就不用考虑这两个字符了,(模拟将这两个字符删除),则当前的结果与这两个字符的前面的字符结尾(word1[i-1],word2[j-1])的结果相同,即dp[i][j] = dp[i-1][j-1]

ii)结尾的字符不等,因为word1[i-1]和word2[j-1]两个字符不等,所以考虑删除元素,这又可以分为3种情况,

 删除word1[i-1] ,也就是不考虑word1[i-1]这个元素了,那么在word1中没有这个元素了,则最终的结果应该是其前一个字符word1[i-2]与word2[j-1]进行比较,看是否相等, 

即 dp[i][j]=dp[i-1][j]+1,因为删除一个元素,所以加1

删除word2[j-1] ,不考虑word2[j-1]这个元素了,那么在word2中就没有这个元素了,则最终的结果应该是word2子串的前一个字符word2[j-2]与word1[i-1]进行比较,看是否相等

即dp[i][j]=dp[i][j-1],因为删除了一个元素,所以加1

删除word1[i-1]和word2[j-1],不考虑word1[i-1]和word2[j-1]这两个元素了,那么在word1和word2中就没有这两个元素了,最终就是word2子串的前一个字符word2[i-2]与word1子串的前一个字符word1[i-2]进行比较 ,即 dp[i][j]=dp[i-1][j-1]+2,因为删除了2个元素,所以加2

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

3)dp数组初始化

根据递推公式,第一行,第一列都要进行初始化,即dp[i][0]   dp[0][j]都需要进行初始化

根据dp数组定义  dp[i][0]代表以i-1结尾的word1和以-1结尾的word2相同的最小操作次数,word2以-1结尾,说明word2是空串,那么要想达到两个子串相等,说明word1需要删除i个元素,需要最少操作i次,所以dp[i][0]=i

同理,dp[0][j]代表以-1结尾的word1和以j-1结尾的word2相同的最小操作次数,word1是空串,此时要想让两个子串相等,word1也需要变为空串,需要将word2中的元素全部删除才可以,即删除j个元素,最少操作j次  ,所以dp[0][j]=j

4)遍历顺序

根据递推公式,从左到右遍历,从上到下遍历

5)打印dp数组

代码,注意定义dp数组的时候,一定要word1.size()+1,一定要加1,因为dp数组的定义是以i-1结尾,最终要遍历到最后一个元素word1.size()-1的时候,才是dp数组的最后一个元素word1.size()减去1为结尾

class Solution {
public:
    int minDistance(string word1, string word2) {
        //定义dp数组
        vector<vector<int>> dp(word1.size()+1,vector<int>(word2.size()+1));
        //初始化dp数组
        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,min(dp[i][j-1]+1,dp[i-1][j-1]+2));
            }
        }
        return dp[word1.size()][word2.size()];
    }
};

上面的代码会出现如下错误

根据出现的错误,将其对应的各个dp数组打印出来,发现dp[0][1]以及dp[1][0]仍是0,并没有初始化成1,所以初始化这里出现了问题

就是因为在初始化的时候,没有将dp[word1.size()][0]和dp[0][word2.size()]初始化

注意初始化数组时,因为是初始化整个dp[i][j],所以将dp[i][0]和dp[0][j]整个进行初始化,所以,i从0到word1.size()都要初始化 ,j从0到word2.size()都要初始化,注意初始化时,一定要使得i<=word1.size(),j<=word2.size(),等号不能丢掉,否则就会在案例出现的时候出现错误

因此,将代码修改如下:

class Solution {
public:
    int minDistance(string word1, string word2) {
        //定义dp数组
        vector<vector<int>> dp(word1.size()+1,vector<int>(word2.size()+1));
        //初始化dp数组
        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,min(dp[i][j-1]+1,dp[i-1][j-1]+2));
            }
        }
        return dp[word1.size()][word2.size()];
    }
};
  • 时间复杂度: O(n * m)
  • 空间复杂度: O(n * m)
流程图

动态规划(思路2)

思路2:本题也可以在求最长公共子序列的基础上进行求解,将word1和word2的最长公共子序列的长度求出来,然后使用word1和word2的长度之和减去2倍的公共子序列的长度,即为所求。

流程

代码

class Solution {
public:
    int minDistance(string word1, string word2) {
        //定义并初始化dp数组
        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]);  
            }
        }
        int result = word1.size()+word2.size()-2*dp[word1.size()][word2.size()];
        return result;
    }
};
  • 时间复杂度: O(n * m)
  • 空间复杂度: O(n * m)

题目2:72 编辑距离

题目链接:编辑距离

对题目的理解

返回将单词word1转换成word2使用最少的操作数,两个单词的长度大于等于0,且均由小写字母组成,操作包括插入一个字符,删除一个字符以及替换一个字符

动态规划

动规五部曲

1)dp数组及下标i的定义

dp[i][j]:以下标i-1结尾的word1和以下标j-1结尾的word2相同的最少操作次数

2)递推公式

还是分为两种情况,两个元素相等以及两个元素不等的情况

1)两个元素word1[i-1]和word2[j-1]相等,则不考虑这两个元素,因为已经相等了,所以不需要对二者进行操作,只需要考虑前面的word1[i-2]和word2[j-2]就行,dp[i][j]=dp[i-1][j-1]

2)两个元素word1[i-1]和word2[j-1]不相等,则需要对元素进行删减以及替换的操作,所以这又可以分为3种情况

i)只考虑word1[i-1],只对这个元素进行操作,当word1[i-1]不等于word2[j-1]时,将word1[i-1]删除,那么此时对于word1而言,就是以word1[i-2]为结尾的子串与word2[j-1]为结尾的子串的最小操作次数的基础上进行操作(删除)加1,因此,dp[i][j]=dp[i-1][j]+1  加1是因为进行了一个删除操作

ii)只考虑word2[j-1],只对这个元素进行操作,当word1[i-1]不等于word2[j-1]时,将word2[j-1]删除,那么对于word2而言,只剩下以word2[j-2]为结尾的子串与word1[i-1]为结尾的子串的最小操作次数的基础上进行操作(删除)加1,dp[i][j]=dp[i][j-1]+1  加1是因为进行了一个删除操作

注:word2添加一个元素,相当于word1删除一个元素,例如 word1 = "ad" ,word2 = "a"word1删除元素'd' 和 word2添加一个元素'd',变成word1="a", word2="ad", 最终的操作数是一样! 

iii)如果word1[i-1]不等于word2[j-1],要使得这两个位置对应的元素相等(dp[i][j]=dp[i-1][j-1],这个等式是word[i-1]和word[j-1]相等的情况,但是此时是要让这两个元素相等,所以需要考虑这两个元素在原来以word1[i-2]为结尾的子串和以word2[j-2]为结尾的子串相同进行操作的基础上加上一个替换的操作就ok),只需要dp[i][j]=dp[i-1][j-1]+1   加1是因为进行了一次替换操作

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

3)dp数组初始化

根据递推公式,第一行和第一列需要初始化,

根据dp数组的定义,dp[i][0]表示以下标i-1为结尾的word1和以下标-1为结尾的word2相同的最少操作次数,而以下标-1为结尾的word2是一个空串,要想使得这两个串的长度相等,那么word1至少需要操作i次,因为word1中含有i个元素

dp[0][j]表示以下标-1为结尾的word1和以下标j-1为结尾的word2相同的最少操作次数,而以下标01结尾的word1是一个空串,要想使得word1和word2的长度相等,那么word2至少需要操作j次,因为word2中含有j个元素

因此初始化如下

注意for循环中一定要是小于等于,一定要有等于,这样才能确保dp数组中的最后一个边界值,即dp[word1.size()][0]和dp[0][word2.size()]初始化了,如果只写小于的话,这组元素就会被落掉,相当于dp[word1.size()][0]和dp[0][word2.size()]没有进行初始化,默认为0

4)遍历顺序

根据递推公式,从左往右遍历,从上到下遍历

5)打印dp数组

最终的结果在dp[word1.size()][word2.size()]中

代码

class Solution {
public:
    int minDistance(string word1, string word2) {
        //定义dp数组
        vector<vector<int>> dp(word1.size()+1,vector<int>(word2.size()+1));
        //初始化dp数组
        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,min(dp[i][j-1]+1,dp[i-1][j-1]+1));
            }
        }
        return dp[word1.size()][word2.size()];
    }
};
  • 时间复杂度: O(n * m)
  • 空间复杂度: O(n * m)

代码流程

删减元素

添加元素

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

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

相关文章

Dagger2使用

在android引入Dagger2库 //引入Dagger2implementation("com.google.dagger:dagger:2.48.1")annotationProcessor ("com.google.dagger:dagger-compiler:2.48.1") 构造器注入 创建一个类 public class Car {//在构造器上面添加dagger的Inject即可Injectp…

现代雷达车载应用——第2章 汽车雷达系统原理 2.1节

经典著作&#xff0c;值得一读&#xff0c;英文原版下载链接【免费】ModernRadarforAutomotiveApplications资源-CSDN文库。 2.1 基本雷达功能 雷达系统通过天线或天线阵列向空间辐射电磁能量。辐射的电磁能量“照亮”周围的目标。“被照亮”的目标拦截一些辐射能量&#xff0…

二十章总结

20.1线程介绍 世间有很多工作都是可以同时完成的。例如&#xff0c;人体可以同时进行呼吸、血液循环、思考问题等活动&#xff1b;用户既可以使用计算机听歌&#xff0c;也可以使用它打印文件。同样&#xff0c;计算机完全可以将多种活动同时进行&#xff0c;这种思想放在 Jav…

配置主机与外网时间服务器同步时间

目录 NTP服务简介 时间管理命令 第一步&#xff1a;更改当前主机所在地的时间 方法一&#xff1a;使用tzselect命令查询需要的时区 1、使用tzselect命令查询需要的时区 2、添加变量到 ~/.bash_profile 文件中&#xff0c;即追加类似的内容&#xff1a; 3、重新连接一个…

Flink(九)【时间语义与水位线】

前言 2023-12-02-20:05&#xff0c;终于写完啦&#xff0c;最近状态不错。刚写完又收到了她的消息哈哈哈哈&#xff0c;开心。 再去全力打拼一次&#xff0c;奋战一场&#xff0c;就算最后打了败仗也无所谓&#xff0c;至少你留下了足迹。 《解忧杂货店》 1、时间语义 …

团队git操作流程

项目的开发要求&#xff1a;&#xff08;1&#xff09;项目组厉员代码提交不少于20次 &#xff08;2&#xff09;项目组厉员每天提交不少于20次 &#xff08;3&#xff09;企业项目开发代码的每天的提交一般提交3-5次 &#xff08;4&#xff09;代码仓库的管理 git的基础操作流…

【CSP】202305-1_重复局面Python实现

文章目录 [toc]试题编号试题名称时间限制内存限制题目背景问题描述输入格式输出格式样例输入样例输出样例说明子任务提示Python实现 试题编号 202305-1 试题名称 重复局面 时间限制 1.0s 内存限制 512.0MB 题目背景 国际象棋在对局时&#xff0c;同一局面连续或间断出现3次或3…

会声会影2024软件还包含了视频教学以及模板素材

会声会影2024中文版是一款加拿大公司Corel发布的视频编软件。会声会影2024官方版支持视频合并、剪辑、屏幕录制、光盘制作、添加特效、字幕和配音等功能&#xff0c;用户可以快速上手。会声会影2024软件还包含了视频教学以及模板素材&#xff0c;让用户剪辑视频更加的轻松。 会…

【Linux 进度条小程序】缓冲区+回车换行

文章目录 回车与换行缓冲区举个栗子fflush函数倒计时小程序进度条小程序 回车与换行 回车和换行是不同的两个概念 回车&#xff1a;\r 使光标回到本行行首。 换行&#xff1a;\n使光标下移一格。 一般我们的键盘上的Enter键是回加换行键 在c语言中 \n 表示回车换行 效果和Ent…

iNet Network Scanner for Mac:简洁高效的WiFi网络扫描软件

随着无线网络的普及&#xff0c;WiFi网络已经成为我们日常生活中必不可少的一部分。无线网络的稳定性和速度对我们的工作和娱乐体验至关重要。因此&#xff0c;一款功能强大、简洁高效的WiFi网络扫描软件非常重要。今天&#xff0c;我们向大家推荐一款优秀的Mac平台WiFi网络扫描…

AI生成工具助力业界,黎万强投资。/微信支付和支付宝境外银行卡全面支持 | 魔法半周报

我有魔法✨为你劈开信息大海❗ 高效获取AIGC的热门事件&#x1f525;&#xff0c;更新AIGC的最新动态&#xff0c;生成相应的魔法简报&#xff0c;节省阅读时间&#x1f47b; &#x1f525;资讯预览 AI应用一年半&#xff0c;IBM HR部省12000小时 华为沉默中&#xff0c;何时…

提高工厂能源效率的关键:工厂能耗监测平台

工业做为能源消耗的重要场所&#xff0c;所以节能减排对工业来讲是一个亟需解决的问题。除了对设备进行更新换代外&#xff0c;还需要能源管理消耗监测平台&#xff0c;帮助企业实现节能减排的目标。 工厂能源消费量非常庞大&#xff0c;能源比较难以监测与控制。传统能源的管…

《微信小程序开发从入门到实战》学习四十二

4.3 云开发文件存储 文件存储功能支持将任意数量和格式的文件&#xff08;如图片和视频&#xff09;保存在云端&#xff0c;支持 以文件夹的形式将文件归类。 在云开发控制台中&#xff0c;可以对云端保存的文件进行管理。 也可以通过文件存储API对文件进行上传、删除、移动…

每日股票价格 - 华为机试真题题解

每日股票价格 - 华为机试真题题解 题目描述 ​ 给定某只股票连续N天的价格列表stockPrices&#xff0c;其中stockPricesi表示股票某天的价格&#xff0c;请生成一个新列表&#xff0c;对应位置输出为:要想等到股票价格上涨&#xff0c;至少需要等待的天数&#xff0c;如果股票…

一个容器中填值,值太多不换行,而是调小字体大小和行高

<!-- clampLineHeight 重计算行高 --> <!-- clampTextSize 重计算字体大小 --> <!-- 这里的div高8mm, 宽6cm, 文本为text --> <div style"height:8mm;width:6cm;text-align:left"><span :style"{ fontSize: clampTextSize(text, 6cm…

Redis——某马点评day03——part2:秒杀业务异步优化

异步秒杀思路 原本的流程是如下所示&#xff0c;必须从开始到创建订单成功才会返回响应。就像饭店里面从下单到上菜都是一个人在服务&#xff0c;就导致服务员利用率很低&#xff0c;后一个顾客要等到前一个顾客上完菜才可以下单。 最简单的优化就是加员工&#xff0c;一次性…

基于单片机自动饮料混合机控制系统设计

**单片机设计介绍&#xff0c;基于单片机自动饮料混合机控制系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机自动饮料混合机控制系统设计是一个涉及多个领域的复杂项目&#xff0c;包括单片机技术、传感器技术…

开发者的福音:TinyVue 组件库文档大优化!类型更详细,描述更清晰!

你好&#xff0c;我是 Kagol。 前言 从今年2月份开源以来&#xff0c;有不少朋友给我们 TinyVue 组件库提了文档优化的建议&#xff0c;这些建议都非常中肯&#xff0c;我们也在持续对文档进行优化&#xff0c;并且从中总结出了大家对于文档优化的一些共性问题&#xff0c;形…

redis应用-分布式锁

目录 什么是分布式锁 分布式锁的基本实现 引入过期时间 引入校验id 引入lua 引入看门狗 引入redlock算法 什么是分布式锁 在一个分布式系统中,也会涉及到多个节点访问同一个公共资源的情况,此时就需要通过锁来做互斥控制,避免出现类似于"线程安全"的问题. 而…

Vis.js教程(三):设置关系图的节点关系指向

1、引言 在 Vis.js教程&#xff08;一&#xff09;基础关系图中&#xff0c;我们介绍了基础关系图的创建&#xff0c;以及关系图的简单样式修改。 这一节我们介绍如何给关系图添加节点之间的关系指向。 2、关系指向添加 // create an array with edgesconst edges new vis…