Leetcode 72. 编辑距离 动态规划 优化 C++实现

2024-09-06 06:36

本文主要是介绍Leetcode 72. 编辑距离 动态规划 优化 C++实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Leetcode 72.编辑距离

问题:给你两个单词 word1  word2, 请返回将 word1 转换成 word2 所使用的最少操作数  。

你可以对一个单词进行如下三种操作:插入一个字符,删除一个字符,替换一个字符。

算法1:递归搜索 + 保存计算结果 = 记忆化搜索

        创建 memo 数组,并赋初始值为 -1,表示还没有被计算过。

        进入 dfs 函数。引用 memo 数组,如果这个字母已经被计算过了就 return memo 的值。有四种情况,两个字母相等,这个位置就不用操作,向前继续递归;如果不相等,可以插入字母、删除字母、替换字母,取操作数最小的一个。

        例如在 word1 中插入字母,那么这个位置的问题就解决了,这个时候要让 word2 的指针前移,继续递归。如果在 word1 中删除字母,那么就要将 word1 的指针前移。如果替换字母,就让 word1 word2 的指针同时前移。

        dfs 中前两行代码表示的意思是,如果在递归过程中出现了 i 或者 j 小于 0 的情况,即 word1 或者 word2 已经遍历完了,那么另一个没有被遍历完的 word 剩余的字母个数就是 j + 1 或者 i + 1 ,这个时候直接 return j + 1 或者 i + 1 即可。

代码:

class Solution {
public:int minDistance(string word1, string word2) {int n = word1.length(), m = word2.length();vector<vector<int>> memo(n, vector<int>(m, -1)); // -1 表示还没有计算过auto dfs = [&](auto&& dfs, int i, int j) -> int {if (i < 0)    return j + 1;if (j < 0)    return i + 1;int& res = memo[i][j]; // 注意这里是引用if (res != -1)    return res; // 之前算过了if (word1[i] == word2[j])   return res = dfs(dfs, i - 1, j - 1);return res = min(min(dfs(dfs, i - 1, j), dfs(dfs, i, j - 1)), dfs(dfs, i - 1, j - 1)) + 1;};return dfs(dfs, n - 1, m - 1); // 递归入口}
};

算法2:1:1 翻译成递推

        创建二维数组 dp ,并赋初始值 0 。初始化第 0 行第 0 列,先赋最大值,即当前位置可能出现的最大值。

        开始循环递推,如果 word1 当前字母与 word2 当前字母相等,则 这个位置的操作数 dp 就等于 dp 前一个格子的值。

代码:

class Solution {
public:int minDistance(string word1, string word2) {int n = word1.length(), m = word2.length();vector<vector<int>> dp(n + 1,vector<int>(m + 1));for(int j = 0;j <= m;j++)   dp[0][j] = j; // 初始化第0行for(int i = 0; i < n; i++){dp[i + 1][0] = i + 1; // 初始化第0列for(int j = 0;j < m;j++)dp[i + 1][j + 1] = word1[i] == word2[j] ? dp[i][j] : min(min(dp[i][j],dp[i + 1][j]),dp[i][j + 1]) + 1;}return dp[n][m];}
};

算法3:空间优化:两个数组(滚动数组)

        通过 算法2 可知,行列表我们只会用到 2 行,每次递推只会取它的上一个格子的值,所以可以利用循环数组,来有效降低空间复杂度。

代码:

class Solution {
public:int minDistance(string word1, string word2) {int n = word1.length(),m = word2.length();vector<vector<int>> dp(2,vector<int>(m + 1));for(int j = 0;j <= m;j++)   dp[0][j] = j;for(int i = 0;i < n;i++){dp[(i + 1) % 2][0] = i + 1;for(int j = 0;j < m;j++)     dp[(i + 1) % 2][j + 1] = word1[i] == word2[j] ? dp[i % 2][j] : min(min(dp[i % 2][j],dp[(i + 1) % 2][j]),dp[i % 2][j + 1]) + 1;}return dp[n % 2][m];}
};

算法3:空间优化:一个数组

        创建一维数组 dp 并赋初始值。

        dp [ 0 ] 相当于原来的 dp [ 0 ] [ ] ,通过内层循环每循环一次就通过 dp [ 0 ] 自增来实现 + 1

        pre 相当于 dp [ i + 1 ] [ j ] ;

        没更新的 dp[ j + 1] 相当于 dp [ i ] [ j + 1] ;

        dp[ j ] 相当于 dp [ i ] [ j ];

        更新后的 dp[ j + 1] 相当于 dp [ i + 1] [ j + 1]

代码:

class Solution {
public:int minDistance(string word1, string word2) {int m = word2.length();vector<int> dp(m + 1);for(int j = 0;j <= m;j++)   dp[j] = j; // iota(dp.begin(), dp.end(), 0);for(char x : word1){int pre = dp[0];dp[0]++; // 对应二维数组方法时行数向下移,即 dp[i+1][0] = i+1for(int j = 0;j < m;j++){int temp = dp[j + 1];dp[j + 1] = x == word2[j] ? pre : min(min(dp[j + 1],dp[j]),pre) + 1;pre = temp;}}return dp[m];}
};

这篇关于Leetcode 72. 编辑距离 动态规划 优化 C++实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1141277

相关文章

Spring Boot整合Redis注解实现增删改查功能(Redis注解使用)

《SpringBoot整合Redis注解实现增删改查功能(Redis注解使用)》文章介绍了如何使用SpringBoot整合Redis注解实现增删改查功能,包括配置、实体类、Repository、Se... 目录配置Redis连接定义实体类创建Repository接口增删改查操作示例插入数据查询数据删除数据更

Java Lettuce 客户端入门到生产的实现步骤

《JavaLettuce客户端入门到生产的实现步骤》本文主要介绍了JavaLettuce客户端入门到生产的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录1 安装依赖MavenGradle2 最小化连接示例3 核心特性速览4 生产环境配置建议5 常见问题

linux ssh如何实现增加访问端口

《linuxssh如何实现增加访问端口》Linux中SSH默认使用22端口,为了增强安全性或满足特定需求,可以通过修改SSH配置来增加或更改SSH访问端口,具体步骤包括修改SSH配置文件、增加或修改... 目录1. 修改 SSH 配置文件2. 增加或修改端口3. 保存并退出编辑器4. 更新防火墙规则使用uf

Java 的ArrayList集合底层实现与最佳实践

《Java的ArrayList集合底层实现与最佳实践》本文主要介绍了Java的ArrayList集合类的核心概念、底层实现、关键成员变量、初始化机制、容量演变、扩容机制、性能分析、核心方法源码解析、... 目录1. 核心概念与底层实现1.1 ArrayList 的本质1.1.1 底层数据结构JDK 1.7

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符