代码随想录Day 45|leetcode题目:115.不同的子序列、583. 两个字符串的删除操作、72. 编辑距离

embedded/2024/9/24 16:07:17/

提示:DDU,供自己复习使用。欢迎大家前来讨论~

文章目录

  • 题目
    • 题目一: 115.不同的子序列
      • 解题思路:
      • 1. 确定dp数组(dp table)以及下标的含义
      • 2. 确定递推公式
      • 3. dp数组如何初始化
      • 4. 确定遍历顺序
      • 5. 举例推导dp数组
      • 代码实现
    • 题目二:583. 两个字符串的删除操作
      • 解题思路:
      • 1. 确定dp数组(dp table)以及下标的含义
      • 2. 确定递推公式
      • 3. dp数组如何初始化
      • 4. 确定遍历顺序
      • 5. 举例推导dp数组
      • 代码实现
      • 动态规划二(求最长公共子序列)
      • 代码实现
    • 题目三:72. 编辑距离
      • 解题思路
      • 1. 确定dp数组(dp table)以及下标的含义
      • 2. 确定递推公式
      • 3. dp数组如何初始化
      • 4. 确定遍历顺序
      • 5. 举例推导dp数组
      • 代码实现
    • 编辑距离总结篇
      • 编辑距离问题

动态规划Part12

题目

题目一: 115.不同的子序列

115. 不同的子序列

解题思路:

这道题目要求判断字符串s是否包含字符串t作为子序列。这里的子序列指的是,t的字符可以不连续,但顺序必须保持一致。解题思路使用动态规划,具体步骤如下:

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

定义二维数组dp[i][j],其中dp[i][j]表示以s的前i-1个字符为结尾的子序列中,出现以t的前j-1个字符为结尾的子序列的个数。

2. 确定递推公式

根据s[i - 1]t[j - 1]是否相等,分两种情况:

  • 相等dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]。因为s[i - 1]可以匹配t[j - 1],也可以不匹配。
  • 不相等dp[i][j] = dp[i - 1][j]。因为s[i - 1]不匹配t[j - 1],只能忽略s[i - 1]

3. dp数组如何初始化

  • dp[i][0] = 1:任何字符串的子序列都至少包含空字符串,所以初始化为1。
  • dp[0][j] = 0:空字符串s不能包含任何非空字符串t作为子序列,所以初始化为0。
  • dp[0][0] = 1:空字符串是自身的子序列。

4. 确定遍历顺序

遍历顺序为从左到右,从上到下,确保每个dp[i][j]的值都是基于已经计算过的dp[i-1][j]dp[i-1][j-1]来计算的。

5. 举例推导dp数组

以具体例子(如s = "baegg"t = "bag")来手动计算dp数组,验证递推公式的正确性。

代码实现

class Solution {
public:int numDistinct(string s, string t) {vector<vector<uint64_t>> dp(s.size() + 1, vector<uint64_t>(t.size() + 1));for (int i = 0; i <= s.size(); i++) dp[i][0] = 1; // 空字符串的子序列计数为1for (int j = 1; j <= t.size(); j++) dp[0][j] = 0; // 空s不能包含非空tfor (int i = 1; i <= s.size(); i++) {for (int j = 1; j <= t.size(); j++) {if (s[i - 1] == t[j - 1]) {dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; // s[i-1]匹配t[j-1]或不匹配} else {dp[i][j] = dp[i - 1][j]; // s[i-1]不匹配t[j-1],忽略s[i-1]}}}return dp[s.size()][t.size()]; // 返回s的所有子序列中包含t的计数}
};

时间复杂度为O(n*m),空间复杂度也为O(n*m),其中n和m分别是字符串s和t的长度。

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

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

解题思路:

这道题目要求找出将两个字符串转换为彼此所需的最少删除次数,可以通过动态规划来解决。以下是详细的解题思路:

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

定义二维数组dp[i][j],其中dp[i][j]表示将字符串word1的前i-1个字符和字符串word2的前j-1个字符转换为彼此所需的最少删除次数。

2. 确定递推公式

根据word1[i - 1]word2[j - 1]是否相等,分两种情况:

  • 相等dp[i][j] = dp[i - 1][j - 1]。因为当两个字符相等时,不需要删除这两个字符。
  • 不相等dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1)。因为当两个字符不相等时,可以选择删除word1的一个字符或者删除word2的一个字符,取两者的最小值。

3. dp数组如何初始化

  • dp[i][0] = i:表示word2为空字符串时,需要删除word1的前i-1个字符。
  • dp[0][j] = j:表示word1为空字符串时,需要删除word2的前j-1个字符。

4. 确定遍历顺序

遍历顺序为从上到下,从左到右,确保每个dp[i][j]的值都是基于已经计算过的dp[i-1][j]dp[i][j-1]来计算的。

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()];}
};

时间复杂度为O(n*m),空间复杂度也为O(n*m),其中n和m分别是字符串word1和word2的长度。

动态规划二(求最长公共子序列)

另一种解法是求两个字符串的最长公共子序列(LCS),然后用两个字符串的总长度减去最长公共子序列的长度的两倍,即为最少删除次数。

代码实现

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;}
};

时间复杂度为O(n*m),空间复杂度为O(n*m)。


题目三:72. 编辑距离

72. 编辑距离

解题思路

编辑距离问题是一个经典的动态规划问题,用于计算两个字符串之间的最小编辑操作次数,使得一个字符串可以转换成另一个字符串。以下是详细的解题思路:

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

定义二维数组dp[i][j],其中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的一个字符:dp[i - 1][j] + 1
    • 删除word2的一个字符:dp[i][j - 1] + 1
    • 替换word1的一个字符:dp[i - 1][j - 1] + 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:表示将word1的前i-1个字符转换为一个空字符串需要删除i次。
  • dp[0][j] = j:表示将一个空字符串转换为word2的前j-1个字符需要添加j次。

4. 确定遍历顺序

遍历顺序为从上到下,从左到右,确保每个dp[i][j]的值都是基于已经计算过的dp[i-1][j]dp[i][j-1]dp[i-1][j-1]来计算的。

5. 举例推导dp数组

以具体例子(如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, 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()];}
};

时间复杂度为O(n*m),空间复杂度也为O(n*m),其中n和m分别是字符串word1和word2的长度。

编辑距离总结篇

  1. 判断子序列:判断一个字符串是否为另一个字符串的子序列,只涉及删除操作。
  2. 不同的子序列:计算一个字符串在另一个字符串子序列中出现的次数,涉及删除操作。
  3. 两个字符串的删除操作:计算使两个字符串相同的最少删除次数,涉及两个字符串的删除操作。

编辑距离问题

问题定义:给定两个字符串word1word2,计算将word1转换成word2的最少操作数,操作包括插入、删除和替换。


http://www.ppmy.cn/embedded/112520.html

相关文章

为什么H.266未能普及?EasyCVR视频编码技术如何填补市场空白

H.266&#xff0c;也被称为Versatile Video Coding&#xff08;VVC&#xff09;&#xff0c;是近年来由MPEG&#xff08;Moving Picture Experts Group&#xff09;和ITU&#xff08;International Telecommunication Union&#xff09;联合开发并发布的新一代国际视频编码标准…

华为CNA VRM搭建(使用vmware worfstartion搭建)

创建虚拟机&#xff1a; 自定义→高级 选择硬件兼容性&#xff1a;默认安装版本&#xff0c;如果未来想要将此虚拟机安装到其他电脑&#xff0c;其他电脑版本过低&#xff0c;此时可以向下兼容&#xff0c;这里我们默认版本 稍后安装操作系统&#xff1a; CNA采用Euler OS系统…

SOMEIP_ETS_111: SD_Empty_Entries_Array

测试目的&#xff1a; 验证DUT能够忽略声明了条目数组长度为零的SubscribeEventgroup消息。 描述 本测试用例旨在确保DUT在接收到一个Entries数组长度为零的SubscribeEventgroup消息时&#xff0c;能够正确地忽略该消息&#xff0c;不对其进行解释或响应。 测试拓扑&#x…

[Web安全 网络安全]-XSS跨脚本攻击

文章目录&#xff1a; 一&#xff1a;前言 1.定义 2.漏洞出现的原因 3.鉴别可能存在XSS漏洞的地方 4.攻击原理 5.危害 6.防御 7.环境 7.1 靶场 7.2 自动扫描工具 7.3 手工测试工具 8.payload是什么 二&#xff1a;常用的标签语法 三&#xff1a;XSS的分类 反射…

安卓玩机工具-----ADB与 FASTBOOT模式 图形化 多功能玩机刷机工具

工具说明 这款工具是英文版。易于使用的工具提供了用于运行 ADB 和 Fastboot 命令的图形用户界面。ADB 功能包括旁加载、安装和卸载应用程序、测试设备以及重新启动到不同的模式。可以使用 fastboot 命令进行设备管理;其中包括检查 Antirollback 和 active slots 等变…

keras和tensorflow可用的一组版本

目录 keras版本&#xff1a;3.5.0tensorflow&#xff1a;2.17.0之前的错误导包现在的正确导包 keras版本&#xff1a;3.5.0 tensorflow&#xff1a;2.17.0 之前的错误导包 其实也不是说错误&#xff0c;就是因为文件位置不对&#xff0c;所以VSCode总是有黄色波浪线&#xff0…

【Git】初识Git

本篇文章的环境是在 Ubuntu/Linux 环境下编写的 文章目录 版本控制器Git 基本操作安装 Git创建 Git 本地仓库配置 Git认识工作区、暂存区、版本库添加文件修改文件版本回退撤销修改删除文件 版本控制器 在日常工作和学习中&#xff0c;老板/老师要求我们修改文档&#xff0c;…

Deep Learning-Based Object Pose Estimation:A Comprehensive Survey

论文&#xff1a;https://arxiv.org/pdf/2405.07801v3 项目&#xff1a;https://github.com/CNJianLiu/Awesome-Object-Pose-Estimation 年份&#xff1a;2024 方向&#xff1a;姿态估计 1. 目标姿态估计定义 估计图像中目标相对于相机的姿态&#xff0c; 目标姿态估计是增…