代码随想录算法训练营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

相关文章

使用Redis实现会话管理的示例代码

《使用Redis实现会话管理的示例代码》文章介绍了如何使用Redis实现会话管理,包括会话的创建、读取、更新和删除操作,通过设置会话超时时间并重置,可以确保会话在用户持续活动期间不会过期,此外,展示了... 目录1. 会话管理的基本概念2. 使用Redis实现会话管理2.1 引入依赖2.2 会话管理基本操作

mybatis-plus分表实现案例(附示例代码)

《mybatis-plus分表实现案例(附示例代码)》MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生,:本文主要介绍my... 目录文档说明数据库水平分表思路1. 为什么要水平分表2. 核心设计要点3.基于数据库水平分表注意事项示例

MySQL游标和触发器的操作流程

《MySQL游标和触发器的操作流程》本文介绍了MySQL中的游标和触发器的使用方法,游标可以对查询结果集进行逐行处理,而触发器则可以在数据表发生更改时自动执行预定义的操作,感兴趣的朋友跟随小编一起看看... 目录游标游标的操作流程1. 定义游标2.打开游标3.利用游标检索数据4.关闭游标例题触发器触发器的基

Nginx服务器部署详细代码实例

《Nginx服务器部署详细代码实例》Nginx是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务,:本文主要介绍Nginx服务器部署的相关资料,文中通过代码... 目录Nginx 服务器SSL/TLS 配置动态脚本反向代理总结Nginx 服务器Nginx是一个‌高性

在C#中分离饼图的某个区域的操作指南

《在C#中分离饼图的某个区域的操作指南》在处理Excel饼图时,我们可能需要将饼图的各个部分分离出来,以使它们更加醒目,Spire.XLS提供了Series.DataFormat.Percent属性,... 目录引言如何设置饼图各分片之间分离宽度的代码示例:从整个饼图中分离单个分片的代码示例:引言在处理

Java实现字符串大小写转换的常用方法

《Java实现字符串大小写转换的常用方法》在Java中,字符串大小写转换是文本处理的核心操作之一,Java提供了多种灵活的方式来实现大小写转换,适用于不同场景和需求,本文将全面解析大小写转换的各种方法... 目录前言核心转换方法1.String类的基础方法2. 考虑区域设置的转换3. 字符级别的转换高级转换

Python列表的创建与删除的操作指南

《Python列表的创建与删除的操作指南》列表(list)是Python中最常用、最灵活的内置数据结构之一,它支持动态扩容、混合类型、嵌套结构,几乎无处不在,但你真的会创建和删除列表吗,本文给大家介绍... 目录一、前言二、列表的创建方式1. 字面量语法(最常用)2. 使用list()构造器3. 列表推导式

HTML5的input标签的`type`属性值详解和代码示例

《HTML5的input标签的`type`属性值详解和代码示例》HTML5的`input`标签提供了多种`type`属性值,用于创建不同类型的输入控件,满足用户输入的多样化需求,从文本输入、密码输入、... 目录一、引言二、文本类输入类型2.1 text2.2 password2.3 textarea(严格

MyBatis-Plus逻辑删除实现过程

《MyBatis-Plus逻辑删除实现过程》本文介绍了MyBatis-Plus如何实现逻辑删除功能,包括自动填充字段、配置与实现步骤、常见应用场景,并展示了如何使用remove方法进行逻辑删除,逻辑删... 目录1. 逻辑删除的必要性编程1.1 逻辑删除的定义1.2 逻辑删php除的优点1.3 适用场景2.

MySQL字符串转数值的方法全解析

《MySQL字符串转数值的方法全解析》在MySQL开发中,字符串与数值的转换是高频操作,本文从隐式转换原理、显式转换方法、典型场景案例、风险防控四个维度系统梳理,助您精准掌握这一核心技能,需要的朋友可... 目录一、隐式转换:自动但需警惕的&ld编程quo;双刃剑”二、显式转换:三大核心方法详解三、典型场景