当前位置: 首页 > news >正文

leetCode 1143.最长公共子序列 动态规划 + 滚动数组

1143. 最长公共子序列 - 力扣(LeetCode)

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

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

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

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

示例 1:

输入:text1 = "abcde", text2 = "ace" 
输出:3  
解释:最长公共子序列是 "ace" ,它的长度为 3 。

示例 2:

输入:text1 = "abc", text2 = "abc"
输出:3
解释:最长公共子序列是 "abc" ,它的长度为 3 。

示例 3:

输入:text1 = "abc", text2 = "def"
输出:0
解释:两个字符串没有公共子序列,返回 0 。

 >>思路和分析

本题和 leetCode 718.最长重复子数组 区别在于这里不要求是连续的了,但是要有相对顺序,即:"ace" 是 "abcde" 的子序列 ,但是 "aec" 不是 "abcde" 的子序列 

>>动规五部曲

1.确定dp数组(dp table)以及下标的含义

dp[i][j] : 长度为 [0,i-1] 字符串 text1 与长度为 [0,j-1]字符串text2最长公共子序列为dp[i][j]

2.确定递推公式

思考:有哪些方向可以推出dp[i][j]

  • text1[i-1] == text[j-1]时,dp[i][j]=dp[i-1][j-1]+1
  • text1[i-1] != text[j-1]时,分两种情况讨论:
    • 情况①: 不看e了,考虑c,就是abc和ac。这两个原字符串的最长公共子序列也可能是abc和ac的最长公共子序列。因为c和e明显不相同,那么可不考虑e了
    • 情况②: 同理,也可以不看c了,考虑e,就是ab和ace。这两个字符串也可能是两个原字符串的最长公共子序列
    • 那么这两种情况应该怎么取呢?这两种情况都有可能是dp[i][j],那么
      • dp[i][j] = max(dp[i][j-1],dp[i-1][j]);
        • 情况①对应dp[i][j-1]
        • 情况②对应dp[i-1][j]
确定递推公式:
if(text1[i-1] == text2[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
else dp[i][j] = max(dp[i-1][j],dp[i][j-1]);

3.dp数组初始化

  • dp[i][0] 应该初始化为0,因为 test1[0,i-1] 空串最长公共子序列是0
  • dp[0][j] 同理也为0
  • 其他下标都是随着递推公式逐步覆盖,初始为多少都可以

故统一初始为0,代码如下:

vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));

4.确定遍历顺序

那么为了在递推的过程中,这三个方向都是经过计算的数值,所以要从前向后从上到下来遍历这个矩阵

5.举例推导dp数组

由上图可看到dp[text1.size()][text2.size()]为最终结果

class Solution {
public:int longestCommonSubsequence(string text1, string text2) {vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));for (int i = 1; i <= text1.size(); i++) {for (int j = 1; j <= text2.size(); j++) {if (text1[i - 1] == text2[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 dp[text1.size()][text2.size()];}
};
  • 时间复杂度: O(n * m),其中 n 和 m 分别为 text1 和 text2 的长度
  • 空间复杂度: O(n * m)

>>优化空间复杂度

class Solution {
public:// 滚动数组int longestCommonSubsequence(string text1, string text2) {vector<int> dp(text2.size() + 1, 0);for(int i=1;i<=text1.size();i++) {int pre = dp[0];for(int j=1;j<=text2.size();j++) {int tmp = dp[j];if(text1[i-1] == text2[j-1]) dp[j] = pre + 1;else dp[j] = max(dp[j-1],dp[j]);pre = tmp;}}return dp[text2.size()];}
};
  • 时间复杂度: O(n * m),其中 n 和 m 分别为 text1 和 text2 的长度
  • 空间复杂度: O(m)

参考文章和视频:

动态规划子序列问题经典题目 | LeetCode:1143.最长公共子序列_哔哩哔哩_bilibili 代码随想录 (programmercarl.com)

来自代码随想录课堂截图:

http://www.lryc.cn/news/190660.html

相关文章:

  • 【C++ Miscellany】继承体系非尾端类设计为抽象类
  • Leetcode236. 二叉树的最近公共祖先
  • Swift SwiftUI CoreData 过滤数据 2
  • 解决maven骨架加载慢问题(亲测解决)
  • Android---java内存模型与线程
  • 23.10.7.sql 里面的DISTINCT
  • mysql面试题38:count(1)、count(*) 与 count(列名) 的区别
  • nodejs+vue+elementui大学生心理健康管理系统
  • 【MySQL】深入解析MySQL双写缓冲区
  • u-boot 编译与运行
  • C++QT-day2
  • 【Acwing187】导弹防御系统(LIS+剪枝+贪心+dfs+迭代加深)
  • 字节大佬带你五分钟掌握接口自动化测试框架
  • 上传文件夹里面的文件后,按树结构的table表格展示
  • 【error】root - Exception during pool initialization
  • 【重拾C语言】九、再论函数(指针、数组、结构体作参数;函数值返回指针、结构体;作用域)
  • Spring WebClient 基于响应式编程模型的HTTP客户端
  • IP真人识别方法与代理IP检测技术
  • MySQL 面试知识脑图 初高级知识点
  • 【数据结构】二叉树的链式结构及实现
  • OpenCV4(C++)—— 创建窗口滑动条来调参
  • 深度学习基础知识 学习率调度器的用法解析
  • 【JUC系列-12】深入理解PriorityQueue的底层原理和基本使用
  • Paddle安装
  • 配置XP虚拟机和Win 10宿主机互相ping通
  • 【机器学习】sklearn对数据预处理
  • 【智慧燃气】智慧燃气解决方案总体概述--终端层、网络层
  • Tomcat隔离web原理和热加载热部署
  • 使用ffmpeg和python脚本下载网络视频m3u8(全网最全面)
  • 【考研408常用数据结构】C/C++实现代码汇总