Leetcode 1143. 最长公共子序列 记忆化搜索 优化 C++实现

2024-09-04 00:12

本文主要是介绍Leetcode 1143. 最长公共子序列 记忆化搜索 优化 C++实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Leetcode 1143. 最长公共子序列

问题:给定两个字符串 text1  text2,返回这两个字符串的最长公共子序列的长度。如果不存在公共子序列,返回 0 。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

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

创建二维数组 memo 并赋初始值  -1-1 代表这个元素没有被计算过。

进入函数 dfs :如果两个字符相同,那么两个指针同时向后移动一个位置,进入下一层递归,计数器 +1

代码:

class Solution {
public:int longestCommonSubsequence(string text1, string text2) {int n = text1.length(),m = text2.length();vector<vector<int>> memo(n,vector<int>(m,-1));// -1代表没被选过auto dfs = [&](auto &&dfs,int i,int j) -> int{if(i < 0 || j < 0)  return 0;int &res = memo[i][j]; // 注意这里是引用if (res != -1) return res; // 之前计算过if (text1[i] == text2[j]) return res = dfs(dfs, i - 1, j - 1) + 1;return res = max(dfs(dfs, i - 1, j), dfs(dfs, i, j - 1));};return dfs(dfs, n - 1, m - 1);}
};

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

创建二维数组 dp ,并赋初始值为 0dp [ i + 1 ] [ j +1 ] 表示 text1 的前 i 个字符与 text2 的前 j 个字符中的最长子序列长度。

当 text1 [ i ] == text2 [ j ] 时,dp [ i + 1 ] [ j +1 ] = dp [ i ] [ j ] + 1

 text1 [ i ]  != text2 [ j ] 时,dp [ i + 1 ] [ j +1 ] = max ( dp [ i ] [ j + 1 ] , dp [ i + 1] [ j ] )

代码:

class Solution {
public:int longestCommonSubsequence(string text1, string text2) {int n = text1.length(), m = text2.length();vector<vector<int>> dp(n + 1, vector<int>(m + 1));for (int i = 0; i < n; i++)for (int j = 0; j < m; j++)dp[i + 1][j + 1] = text1[i] == text2[j] ? dp[i][j] + 1 : max(dp[i][j + 1], dp[i + 1][j]);return dp[n][m];}
};

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

通过算法2可以发现,二维数组 dp 的列空间只用到了相邻的两个位置,即 dp [ i + 1 ] [ ] dp [ i ] [ ] ,所以我们可以把列空间优化,即把 dp 数组变为 2行 m+1 列 ,通过取余( % )操作,可以循环利用这两个空间。

最后 return dp [n % 2 ] [ m ] 的原因是要从 dp[ 0 ][ 0 ] 开始递归,所以 假设 n = 5 n % 2 1 ,我们就要 return dp [ 1 ] [ m ]

代码:

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

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

dp [ j + 1 ] 表示 text2 前 j 个元素与当前遍历到的 text1 的元素的最长子序列长度。

pre 表示先前 dp [ j + 1 ] 的状态,当 j 更新后,也就是此时的 dp [ j ] 的上一个值(没在本轮更新过的值)。这个操作保证了在遍历 text2 时,如果出现相同的字母,不会重复计算。例如,当前遍历到了 text1 的第一个 a ,刚好 text2 aca ,遍历 text2 过程中,遍历到第一个 a 时,个数 + 1,遍历到第二个 时,pre 等于这个位置之前的值,因为 a == a ,所以 dp = pre + 1 ,这样不会出现元素重复计算的情况,因为无论 text2 的这个元素是否与 text1 当前正遍历到的元素 相等,他们更新的 dp 值都相同,因为如果这两个元素不相等,如果前面的 dp 已经更新,那么此 dp 也会通过 max 操作更新。

代码中出现 j + 1 的原因是因为 text1 text2 中元素都是从下标 0 开始存储,而 dp 数组从下标 1 开始存储。

代码:

class Solution {
public:int longestCommonSubsequence(string text1, string text2) {int m = text2.length();vector<int> dp(m+1);for(char x : text1)for(int j = 0,pre = 0;j < m;j++){int temp = dp[j + 1];dp[j + 1] = x == text2[j] ? pre + 1 : max(dp[j],dp[j + 1]);pre = temp;}return dp[m];}
};

这篇关于Leetcode 1143. 最长公共子序列 记忆化搜索 优化 C++实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

AJAX请求上传下载进度监控实现方式

《AJAX请求上传下载进度监控实现方式》在日常Web开发中,AJAX(AsynchronousJavaScriptandXML)被广泛用于异步请求数据,而无需刷新整个页面,:本文主要介绍AJAX请... 目录1. 前言2. 基于XMLHttpRequest的进度监控2.1 基础版文件上传监控2.2 增强版多

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Redis分片集群的实现

《Redis分片集群的实现》Redis分片集群是一种将Redis数据库分散到多个节点上的方式,以提供更高的性能和可伸缩性,本文主要介绍了Redis分片集群的实现,具有一定的参考价值,感兴趣的可以了解一... 目录1. Redis Cluster的核心概念哈希槽(Hash Slots)主从复制与故障转移2.

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

使用Python实现一键隐藏屏幕并锁定输入

《使用Python实现一键隐藏屏幕并锁定输入》本文主要介绍了使用Python编写一个一键隐藏屏幕并锁定输入的黑科技程序,能够在指定热键触发后立即遮挡屏幕,并禁止一切键盘鼠标输入,这样就再也不用担心自己... 目录1. 概述2. 功能亮点3.代码实现4.使用方法5. 展示效果6. 代码优化与拓展7. 总结1.

Mybatis 传参与排序模糊查询功能实现

《Mybatis传参与排序模糊查询功能实现》:本文主要介绍Mybatis传参与排序模糊查询功能实现,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、#{ }和${ }传参的区别二、排序三、like查询四、数据库连接池五、mysql 开发企业规范一、#{ }和${ }传参的

Docker镜像修改hosts及dockerfile修改hosts文件的实现方式

《Docker镜像修改hosts及dockerfile修改hosts文件的实现方式》:本文主要介绍Docker镜像修改hosts及dockerfile修改hosts文件的实现方式,具有很好的参考价... 目录docker镜像修改hosts及dockerfile修改hosts文件准备 dockerfile 文

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat