代码随想录算法训练营Day55 | 583.两个字符串的删除操作、72.编辑距离

本文主要是介绍代码随想录算法训练营Day55 | 583.两个字符串的删除操作、72.编辑距离,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

最开始想到的是基于最长公共子序列的写法:删除公共子序列以外的字符,两个字符串就相同了

int minDistance0(string word1, string word2) {int n = word1.size();int m = word2.size();vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));for (int i = 1; i <= n; ++i) {for (int j = 1; j <= m; ++j) {if (word1[i - 1] == word2[j - 1])dp[i][j] = dp[i - 1][j - 1] + 1;elsedp[i][j] = std::max(dp[i][j - 1], dp[i - 1][j]); }}// 删除最长公共子序列以外的字符return n + m - 2 * dp[n][m];
}

 另一种基于题意定义DP数组的写法:

题目求需要进行删除的最小操作数,那么就将DP数组定义为目前的最小删除次数

1、DP数组定义: dp[i][j] 表示以word2[j - 1] 为结尾的子串和 word1[i - 1] 为结尾的子串达到相同需要的最小删除操作次数

2、DP数组初始化:dp[0][0]初始化为0,其余首列与首行元素初始化为i / j(有 i / j 个字符的字符串与一个空字符串达到相同需要进行 i / j 次删除操作)

3、递推公式

        · 当word1[i - 1] == word2[j - 1]时,不需要进行删除操作:

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

        · 当word1[i - 1] != word2[j - 1]时,dp[i][j]可以由三个方向取最小转移得到:

                方向1——dp[i][j - 1],在此基础上删除 word1[i - 1]

                方向2——dp[i - 1][j],在此基础上删除 word2[j - 1]

                方向3——dp[i - 1][j - 1],在此基础上删除 word1[i - 1] 和 word2[j - 1]

            最后的递推公式:dp[i][j] = min(dp[i - 1][j - 1] + 2, min(dp[i][j - 1] + 1, dp[i - 1][j] + 1))

4、遍历顺序:i 依赖 i - 1,j 依赖 j - 1,所以从左向右从上向下遍历

int minDistance(string word1, string word2) {// dp[i][j]表示达到相同需要的最小删除操作次数vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));// 除dp[0][0]外,dp[i][0]和dp[0][j]初始化为i/jfor (int i = 1; i <= word1.size(); ++i)dp[i][0] = i;for (int j = 1; 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];// 三个方向取最小值elsedp[i][j] = std::min(dp[i - 1][j - 1] + 2, std::min(dp[i][j - 1] + 1, dp[i - 1][j] + 1));}}return dp[word1.size()][word2.size()];
}

72.编辑距离

这题仍然是根据题意定义DP数组,重点是理清楚删除、替换、插入三种操作的状态转移

1、DP数组定义: dp[i][j] 表示以 word1[i - 1] 为结尾的子串想要达到与 word2[j - 1] 为结尾的子串相同,需要的最小编辑次数

2、DP数组初始化:dp[0][0]初始化为0,其余首列与首行元素初始化为i / j(有 i / j 个字符的字符串与一个空字符串达到相同需要进行 i / j 次删除操作)

3、递推公式

        · 当word1[i - 1] == word2[j - 1]时,不需要进行编辑操作:

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

        · 当word1[i - 1] != word2[j - 1]时,dp[i][j]可以由三种操作取最小转移得到:

                删除 —— 将word[i - 1]删除,在 dp[i - 1][j] 的基础上+1,

                替换 —— 将 word1[i - 1] 替换为 word2[j - 1],在 dp[i - 1][i - 1] 的基础上+1

                插入 —— 将一个等于 word2[j - 1] 的值插在原先word1[i - 1]的位置上,在 dp[i][j - 1] 的基础上+1

            最后的递推公式:dp[i][j] = min(dp[i - 1][j] + 1, min(dp[i - 1][j - 1] + 1, dp[i][j - 1] + 1))

4、遍历顺序:i 依赖 i - 1,j 依赖 j - 1,所以从左向右从上向下遍历

int minDistance(string word1, string word2) {// dp[i][j]表示达到相同需要的最小编辑操作次数vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));for (int i = 1; i <= word1.size(); ++i)dp[i][0] = i;for (int j = 1; 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 - 1][j] + 1		(在dp[i - 1][j] + 1的基础上删除word[i - 1])// 替换:dp[i - 1][j - 1] + 1	(在dp[i - 1][i - 1]的基础上将word1[i - 1]替换为word2[j - 1])// 插入:dp[i][j - 1] + 1		(在dp[i][j - 1]的基础上插入一个等于word2[j - 1]的值)dp[i][j] = std::min(dp[i - 1][j] + 1, std::min(dp[i - 1][j - 1] + 1, dp[i][j - 1] + 1));}}}return dp[word1.size()][word2.size()];
}

编辑距离总结

这类题目做多了还是能找到些套路的:

1、DP数组定义

        · DP数组的定义一般是题目要求什么就定义成什么,

        · dp[i][j] 一般表示的是以 word1[i - 1] 为结尾的子串和 word2[j - 1] 为结尾的子串

2、DP数组初始化:结合题意,一般首行和首列的初始化最为重要

3、递推公式

        分析状态转移可以分为“基础”“新增”两部分:

        · 基础:继承之前的状态,如果当前值匹配一般只要进行这步操作

        · 新增:在之前状态的基础上增加操作时新增的值,如果当前值不匹配一般需要额外进行这步操作

4、遍历顺序:结合题意,一般是 i 依赖 i - 1,j 依赖 j - 1,所以大部分情况是从左向右从上向下遍历

这篇关于代码随想录算法训练营Day55 | 583.两个字符串的删除操作、72.编辑距离的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

python操作redis基础

《python操作redis基础》Redis(RemoteDictionaryServer)是一个开源的、基于内存的键值对(Key-Value)存储系统,它通常用作数据库、缓存和消息代理,这篇文章... 目录1. Redis 简介2. 前提条件3. 安装 python Redis 客户端库4. 连接到 Re

通过cmd获取网卡速率的代码

《通过cmd获取网卡速率的代码》今天从群里看到通过bat获取网卡速率两段代码,感觉还不错,学习bat的朋友可以参考一下... 1、本机有线网卡支持的最高速度:%v%@echo off & setlocal enabledelayedexpansionecho 代码开始echo 65001编码获取: >

Java集成Onlyoffice的示例代码及场景分析

《Java集成Onlyoffice的示例代码及场景分析》:本文主要介绍Java集成Onlyoffice的示例代码及场景分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 需求场景:实现文档的在线编辑,团队协作总结:两个接口 + 前端页面 + 配置项接口1:一个接口,将o

Java Stream.reduce()方法操作实际案例讲解

《JavaStream.reduce()方法操作实际案例讲解》reduce是JavaStreamAPI中的一个核心操作,用于将流中的元素组合起来产生单个结果,:本文主要介绍JavaStream.... 目录一、reduce的基本概念1. 什么是reduce操作2. reduce方法的三种形式二、reduce

golang float和科学计数法转字符串的实现方式

《golangfloat和科学计数法转字符串的实现方式》:本文主要介绍golangfloat和科学计数法转字符串的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望... 目录golang float和科学计数法转字符串需要对float转字符串做处理总结golang float

Python如何判断字符串中是否包含特殊字符并替换

《Python如何判断字符串中是否包含特殊字符并替换》这篇文章主要为大家详细介绍了如何使用Python实现判断字符串中是否包含特殊字符并使用空字符串替换掉,文中的示例代码讲解详细,感兴趣的小伙伴可以了... 目录python判断字符串中是否包含特殊字符方法一:使用正则表达式方法二:手动检查特定字符Pytho

SpringBoot实现Kafka动态反序列化的完整代码

《SpringBoot实现Kafka动态反序列化的完整代码》在分布式系统中,Kafka作为高吞吐量的消息队列,常常需要处理来自不同主题(Topic)的异构数据,不同的业务场景可能要求对同一消费者组内的... 目录引言一、问题背景1.1 动态反序列化的需求1.2 常见问题二、动态反序列化的核心方案2.1 ht

MySQL表空间结构详解表空间到段页操作

《MySQL表空间结构详解表空间到段页操作》在MySQL架构和存储引擎专题中介绍了使用不同存储引擎创建表时生成的表空间数据文件,在本章节主要介绍使用InnoDB存储引擎创建表时生成的表空间数据文件,对... 目录️‍一、什么是表空间结构1.1 表空间与表空间文件的关系是什么?️‍二、用户数据在表空间中是怎么

IDEA实现回退提交的git代码(四种常见场景)

《IDEA实现回退提交的git代码(四种常见场景)》:本文主要介绍IDEA实现回退提交的git代码(四种常见场景),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1.已提交commit,还未push到远端(Undo Commit)2.已提交commit并push到

Kotlin Compose Button 实现长按监听并实现动画效果(完整代码)

《KotlinComposeButton实现长按监听并实现动画效果(完整代码)》想要实现长按按钮开始录音,松开发送的功能,因此为了实现这些功能就需要自己写一个Button来解决问题,下面小编给大... 目录Button 实现原理1. Surface 的作用(关键)2. InteractionSource3.