代码随想录刷题day56 583. 两个字符串的删除操作;72. 编辑距离;编辑距离总结篇

news2024/11/25 20:43:12

代码随想录刷题day56 583. 两个字符串的删除操作;72. 编辑距离;编辑距离总结篇

关于编辑距离的一些题目。

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

583. 两个字符串的删除操作 - 力扣(Leetcode)

化简这一步不容易想到。原理就是两个都删除相当于删除一个再多操作一次。

还有一个思路就是求出最长公共子序列,也是一种方法。

思路

动态规划一

两个字符串可以相互删了,这种题目也知道用动态规划的思路来解,动规五部曲,分析如下:

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

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

这里dp数组的定义有点点绕,大家要撸清思路。

  1. 确定递推公式
  • 当word1[i - 1] 与 word2[j - 1]相同的时候
  • 当word1[i - 1] 与 word2[j - 1]不相同的时候

当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 - 1][j - 1] + 1等于 dp[i - 1][j] 或 dp[i][j - 1],所以递推公式可简化为:dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);

  1. dp数组如何初始化

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

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

dp[0][j]的话同理,所以代码如下:

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;
  1. 确定遍历顺序

从递推公式 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]都是根据左上方、正上方、正左方推出来的。

所以遍历的时候一定是从上到下,从左到右,这样保证dp[i][j]可以根据之前计算出来的数值进行计算。

  1. 举例推导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. 编辑距离

72. Edit Distance - 力扣(Leetcode)

关键是要想明白word2减一个相当于word1加一个这个原理。以及如何用递推公式的方法表示每种修改的可能。

思路

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

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

这里在强调一下:为啥要表示下标i-1为结尾的字符串呢,为啥不表示下标i为结尾的字符串呢?

用i来表示也可以! 但我统一以下标i-1为结尾的字符串,在下面的递归公式中会容易理解一点。

2. 确定递推公式

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

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

也就是如上4种情况。

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

此时可能有同学有点不明白,为啥要即dp[i][j] = dp[i - 1][j - 1]呢?

那么就在回顾上面讲过的dp[i][j]的定义,word1[i - 1]word2[j - 1]相等了,那么就不用编辑了,以下标i-2为结尾的字符串word1和以下标j-2为结尾的字符串word2的最近编辑距离dp[i - 1][j - 1]就是 dp[i][j]了。

在下面的讲解中,如果哪里看不懂,就回想一下dp[i][j]的定义,就明白了。

在整个动规的过程中,最为关键就是正确理解dp[i][j]的定义!

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", 最终的操作数是一样! dp数组如下图所示意的:

          a                         a     d
   +-----+-----+             +-----+-----+-----+
   |  0  |  1  |             |  0  |  1  |  2  |
   +-----+-----+   ===>      +-----+-----+-----+
 a |  1  |  0  |           a |  1  |  0  |  1  |
   +-----+-----+             +-----+-----+-----+
 d |  2  |  1  |
   +-----+-----+

操作三:替换元素,word1替换word1[i - 1],使其与word2[j - 1]相同,此时不用增加元素,那么以下标i-2为结尾的word1j-2为结尾的word2的最近编辑距离 加上一个替换元素的操作。

dp[i][j] = dp[i - 1][j - 1] + 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;

递归公式代码如下:

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 - 1][j], dp[i][j - 1]}) + 1;
}

3. dp数组如何初始化

再回顾一下dp[i][j]的定义:

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

那么dp[i][0] 和 dp[0][j] 表示什么呢?

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

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

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

所以C++代码如下:

for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
for (int j = 0; j <= word2.size(); j++) 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矩阵中一定是从左到右从上到下去遍历。

代码如下:

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 - 1][j], dp[i][j - 1]}) + 1;
        }
    }
}

5. 举例推导dp数组

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

在这里插入图片描述

以上动规五部分析完毕,C++代码如下:

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 = 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 - 1][j], dp[i][j - 1]}) + 1;
                }
            }
        }
        return dp[word1.size()][word2.size()];
    }
};
             dp[i][j] = dp[i - 1][j - 1];
                }
                else {
                    dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
                }
            }
        }
        return dp[word1.size()][word2.size()];
    }
};

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

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

相关文章

华为云大数据BI赋能企业数字化发展

企业在数字化转型过程中面临着不少挑战&#xff0c;比如数据整合能力有限、不足的需求快速响应能力、缺乏数据管理机制和保障、自建分析平台成本高等等。所以各大企业都希望通过一个大数据智能系统来全方位帮助企业处理数据分析&#xff0c;做好智能决策。因此&#xff0c;对于…

基于SOPHON TPU架构实现 Faiss 的两个查询接口

文章目录1. Faiss 简介2. 距离度量3. 在 Sophon TPU 上的接口实现3.1 Sophon TPU3.2 indexflat 实现3.3 indexPQ 实现 1. Faiss 简介 Faiss 库是 Facebook 开发的一个用于稠密向量相似性搜索和聚类的库&#xff0c;该库包含有诸多向量相似性搜索的算法。向量相似性搜索是将一…

【Pytorch】第 2 章 :马尔可夫决策过程和动态规划

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

python之对比两张图像的相似度

python之图像背景识别 本着结合实际工作&#xff0c;实际落地并已应用的态度去码文。 python之对比两张图像的相似度 需求&#xff1a;在某个手机端项目中&#xff0c;有多个页面图片&#xff0c;但每个图片都做了相应的修改&#xff0c;由于这种图片非常多&#xff0c;高达上万…

澳亚通过聆讯:上半年营收近3亿美元 元气森林与新希望乳业是股东

雷递网 雷建平 12月6日澳亚集团有限公司&#xff08;简称&#xff1a;“澳亚集团”&#xff09;日前通过聆讯&#xff0c;准备在港交所上市。澳亚集团是2022年10月中旬递交招股书&#xff0c;不到2个月时间&#xff0c;澳亚集团就通过上市聆讯&#xff0c;这在最近两年的港交所…

小型扫雪机结构设计

目 录 摘 要 I ABSTRACT II 1、绪论 1 1.1 选题意义 1 1.2小型扫雪机国内发展现状 1 1.2.1国内小型扫雪机械现状 1 1.2.2犁式小型扫雪机 2 1.2.3旋切式小型扫雪机 2 1.2.4国内小型扫雪机械的发展方向 3 1.3国外道路小型扫雪机械技术发展概况 3 1.3.1综合式扫雪 3 1.3.2融雪扫雪…

【华为上机真题 2022】数组组成的最小数字

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…

深入探索 Kubernetes 网络模型和网络通信

Kubernetes 定义了一种简单、一致的网络模型&#xff0c;基于扁平网络结构的设计&#xff0c;无需将主机端口与网络端口进行映射便可以进行高效地通讯&#xff0c;也无需其他组件进行转发。该模型也使应用程序很容易从虚拟机或者主机物理机迁移到 Kubernetes 管理的 pod 中。 …

PR-39 TFA 是富含脯氨酸和精氨酸的天然抗菌肽

PR-39 TFA 是富含脯氨酸和精氨酸的天然抗菌肽&#xff0c;是一种非竞争性&#xff0c;可逆和变构的蛋白酶体 (proteasome) 抑制剂。PR-39 TFA 可逆地结合到蛋白酶体的 α7 亚基上&#xff0c;并通过泛素-蛋白酶体途径阻断 NF-κB 抑制剂 IκBα 的降解。PR-39 TFA 刺激小鼠的血…

Java中的final关键字,你清楚吗?

前言 在学习Java基础阶段应该都认识关键字 final,在声明常量和匿名内部类时都会用到它。我们最熟悉的 String 类就是 final类&#xff0c;如果经常查看API源码&#xff0c;肯定还会遇到其他 final类。本篇就来深入了解一下关键字 final&#xff0c;加深对它的运用。 概览 可用…

java计算机毕业设计ssm线上拍卖系统设计6luor(附源码、数据库)

java计算机毕业设计ssm线上拍卖系统设计6luor&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff0…

CRC 循环冗余检验【计网必考】

CRC 循环冗余检验作为一个重点&#xff0c;也是数据链路层必考的一个考点&#xff0c;所以我把差错检测单独拿出来分析一起看一下。总结不易&#xff0c;一个简单的攒&#xff0c;Thanks♪(&#xff65;ω&#xff65;)&#xff89; 目录 一、介绍及工作原理 二、校验计算过程…

zookeeper四字命令_java培训

zookeeper支持某些特定的四字命令&#xff0c;他们大多是用来查询ZK服务的当前状态及相关信息的&#xff0c; 通过telnet或nc向zookeeper提交相应命令&#xff0c;如&#xff1a;echo ruok | nc 127.0.0.1 2181 运行公式&#xff1a;echo 四字命令 | nc 主机IP zookeeper端口…

一文读懂Linux内存分配策略

转载&#xff1a;一文读懂Linux内存分配策略-今日头条 (toutiao.com) 在 Linux 操作系统中&#xff0c;虚拟地址空间的内部又被分为内核空间和用户空间两部分&#xff0c;不同位数的系统&#xff0c;地址空间的范围也不同。比如最常见的 32 位和 64 位系统&#xff0c;如下所示…

r语言中对LASSO回归,Ridge岭回归和弹性网络Elastic Net模型实现

原文链接&#xff1a;http://tecdat.cn/?p3795Glmnet是一个通过惩罚最大似然关系拟合广义线性模型的软件包。正则化路径是针对正则化参数λ的值网格处的lasso或Elastic Net&#xff08;弹性网络&#xff09;惩罚值计算的&#xff08;点击文末“阅读原文”获取完整代码数据&…

[附源码]JAVA毕业设计社区图书馆借阅管理系统(系统+LW)

[附源码]JAVA毕业设计社区图书馆借阅管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项…

【微服务】版本确认完成,传统方式安装Nacos

目录安装Nacos1.4.1【微服务】SpringCloud和SpringBoot版本选择 【微服务】传统方式安装Nacos 安装Nacos1.4.1 Github地址&#xff1a;https://github.com/alibaba/nacos/releases Nacos1.4.1版本下载地址&#xff1a;https://github.com/alibaba/nacos/releases/download/1.…

170-本地WIFI测试环境配置IP

前几天的时候 博客被删了好多好多篇 算一下 现在是169 按道理的话应该总数是1169的 但是现在只剩下1157了 所以就是被删除了12篇 算了 问题不大 被删了就被删了吧 最近心情真的很不好 五月份的事情一直到现在还是没有走出来 我估计可能要等到下一次自己赚到钱了之后…

基于轨迹优化的自动驾驶汽车跟随自行车模型动力学控制(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 本次使用轨迹优化技术来控制汽车。假设汽车遵循自行车模型的动力学。为了实现稳定和安全的跟踪&#xff0c;我们使用了离散时间…

微信内嵌H5调用相机及支付相关问题

前言 进来项目在做公众号&#xff0c;遇到了一些问题及解决方案&#xff0c;在这里进行记录及分享&#xff0c;希望给大家带来一丝帮助 手机上控制台调试我建议使用vConsole(npm install vconsole) 微信内嵌H5的相机调用 微信内嵌H5我们需要调用扫码功能&#xff0c;则需要用…