代码随想录Day 45|leetcode题目:115.不同的子序列、583. 两个字符串的删除操作、72. 编辑距离
提示: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的长度。
编辑距离总结篇
- 判断子序列:判断一个字符串是否为另一个字符串的子序列,只涉及删除操作。
- 不同的子序列:计算一个字符串在另一个字符串子序列中出现的次数,涉及删除操作。
- 两个字符串的删除操作:计算使两个字符串相同的最少删除次数,涉及两个字符串的删除操作。
编辑距离问题
问题定义:给定两个字符串word1
和word2
,计算将word1
转换成word2
的最少操作数,操作包括插入、删除和替换。
相关文章:
代码随想录Day 45|leetcode题目:115.不同的子序列、583. 两个字符串的删除操作、72. 编辑距离
提示:DDU,供自己复习使用。欢迎大家前来讨论~ 文章目录 题目题目一: 115.不同的子序列解题思路:1. 确定dp数组(dp table)以及下标的含义2. 确定递推公式3. dp数组如何初始化4. 确定遍历顺序5. 举例推导dp数…...

浮点数在内存中的存储详解(超详细)
目录 1. 浮点数存储规则 2. IEEE754规定: 3. 关于M的说明: 4. 关于E的说明: 5. 关于S的说明: 6.浮点数从内存中取出(三种情况) 情况1:E不全为0或不全为1 情况2:E全为0 情况3&a…...

Maven下载安装
下载 下载地址:Maven – Download Apache Maven 选择合适的版本进行下载 windows&Linux安装 1, 解压apache-maven-3.6.1.rar即安装完成 2, 配置环境变量MAVEN_HOME为安装路径,并将MAVEN_HOME的bin目录配置到PATH下 3,…...

Qt:Q_GLOBAL_STATIC实现单例(附带单例使用和内存管理)
前言 本文主要写Q_GLOBAL_STATIC实现单例以及单例的释放,网上很多教程只有单例的创建,但是并没有告诉我们单例的内存管理,这就很头疼。 正文 使用 Qt 的 Q_GLOBAL_STATIC // Singleton.h #ifndef SINGLETON_H #define SINGLETON_H#includ…...
URL.createObjectURL 与 FileReader:Web 文件处理两大法宝的对比
URL.createObjectURL 与 FileReader:Web 文件处理两大法宝的对比 在Web开发中,处理用户上传的文件是一项常见且重要的任务。URL.createObjectURL和FileReader是两种常用于此目的的Web API,它们各有特点,适用于不同的场景。本文将…...

零基础考过软考信息系统项目管理师经验分享
选择适合的课程:如果你是零基础,建议找一些专门针对新手的课程,讲解通俗易懂。 刷题至关重要:软考的题库很庞大,多做题是必须的。 做好笔记和复习:上课时要做好笔记,课后及时复习,…...

机器学习课程学习周报十二
机器学习课程学习周报十二 文章目录 机器学习课程学习周报十二摘要Abstract一、机器学习部分1.1 fGAN: General Framework of GAN1.2 CycleGAN1.3 Auto-Encoder1.4 概率论复习(一) 总结 摘要 本周的学习内容涵盖了fGAN框架、CycleGAN、自编码器以及概率…...
python多线程程序设计 之二
python多线程程序设计 之二 线程同步机制lock对象acquirereleaselocked RLock对象条件变量条件变量应用实列实列代码 线程同步机制 lock对象 原语锁是一种同步原语,锁定时不属于特定线程。在Python中,它是目前可用的最低级别的同步原语,由_…...
k8s用StatefulSet部署redis
redis-config.yaml (配置文件) apiVersion: v1 kind: ConfigMap metadata:name: redis-config data:redis.conf: |# Redis general configuration bind 0.0.0.0 protected-mode no port 6379 dir /data appendonly yesse…...
flink on k8s
1.修改host文件 vi /etc/hosts 添加如下内容 这样搭集群的时候就不用记ip了 #::1 localhost localhost.localdomain localhost6 localhost6.localdomain6127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 165.154.221.97 tlb-001 k8s01 k8s-m…...

Java集合(八股)
这里写目录标题 Collection 接口List 接口ArrayList 简述 1. ArrayList 和 LinkedList 区别?⭐️⭐️⭐️⭐️2. ArrayList 和 Array 的区别?⭐️⭐️⭐️ArrayList 和 Vector 区别?⭐️⭐️ArrayList 的扩容机制?⭐️⭐️⭐️ Qu…...
python+adb
#!/usr/bin/python env # -*- coding: utf-8 -*- import os import sys import subprocess from time import sleepimport logging logging.basicConfig(levellogging.DEBUG) class ScreenCapture():def get_screen_size(self):"""获取手机分辨率""&q…...

AIGC文本生成
文本生成是一种人工智能技术,它基于深度学习算法,根据给定的提示信息创作出有逻辑、连贯的文本内容。 文本生成所需的输入(提示或Prompt)可以是简单的关键词、一句话概述或是更复杂的指令和上下文信息。文本生成模型通过分析大量…...
系统架构设计师教程 第5章 5.4 软件测试 笔记
5.4 软件测试 5.4.1 测试方法 ★★★★★ 软件测试方法的分类有很多种, 以测试过程中程序执行状态为依据可分为静态测试 (Static Testing,ST) 和动态测试 (Dynamic Testing,DT); 以具体实现算法细节和系统内部结构的相关情况为根据可分黑盒测试、白盒测试和灰盒测…...
ASPICE评估全流程解析:汽车软件开发组织能力的系统化评估
ASPICE(Automotive SPICE)评估的过程是一个系统化和详尽的流程,旨在评估汽车软件开发组织在软件开发过程方面的能力。 以下是ASPICE评估过程的详细描述: 1. 评估准备阶段 a. 确定评估目标和范围 明确评估的目标,如评…...

合并RAR分卷压缩包
因为文件压缩之后体积仍然过大,大家可能会选择进行分卷压缩,那么rar分卷压缩包之后如何合并成一个压缩包文件呢?今天我们来学习rar分卷压缩包,合并成一个的方法。 最基础的方法就是将分卷压缩包解压出来之后,再将文件…...

重生奇迹MU 想去哪就去哪玩 轻松玩转翅膀属性
在重生奇迹MU这个游戏中,玩家需要扫荡各种怪物,勇斗BOSS,与其他玩家激战。在这个充满冒险的旅程中,翅膀是最重要的装备之一。拥有一个属性强大的翅膀,代表着玩家的成长与强大。穿上它,加速你的冒险之旅吧&a…...

Lnux-gcc/g++使用
目录 1.gcc/g介绍 1.什么是 gcc / g 2.gcc/g指令格式 2. gcc / g 实现程序翻译的过程 1.预处理(进行宏替换) 2.编译(生成汇编) 3.汇编(生成机器可识别代码) 4.连接(生成可执行文件或库文件) 1.gcc/g介绍 1.什么…...
用Python创建一个键盘输入捕获程序
目录 简介 环境准备 安装依赖 项目结构 编写代码 1. 导入库 2. 定义回调函数 3. 启动键盘监听器 4. 整合代码 运行程序 结论 简介 在这篇博文中,我们将探索如何使用Python编写一个简单的键盘输入捕获程序。这个程序将实时捕获用户的键盘输入并在控制台中显示出来。…...

Mybatis中Like模糊查询三种处理方式
目录 Mybatis中Like模糊查询三种处理方式 1.通过单引号拼接${} 1)mapper接口 2)Mapper.xml 3)测试代码 4) 测试结果 2.通过concat()函数拼接(个人推荐使用这种) 1)mapper接口 2)Mapper.xml 3)测试代码 4) 测…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...