leetCode 392. 判断子序列 动态规划 + 优化空间 / 双指针 等多种解法

392. 判断子序列 - 力扣(LeetCode)


给定字符串 s 和 t ,判断 s 是否为 t 的子序列。字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

进阶:如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?


示例 1:

输入:s = "abc", t = "ahbgdc"
输出:true

示例 2:

输入:s = "axc", t = "ahbgdc"
输出:false

>>思路和分析

  • 只需要计算删除的情况

(一)动规五部曲

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

  • dp[i][j] : 表示以下标 i-1 为结尾的字符串 s ,和以下标 j-1 为结尾的字符串 t ,相同子序列的长度为dp[i][j]

2.确定递推公式

  • ① if(s[i-1] == t[j-1]) dp[i][j] = dp[i-1][j-1] + 1
  • ② if(s[i-1] != t[j-1]) dp[i][j] = dp[i][j-1] 

如果 s[i-1] == t[j-1],说明当前在遍历串t 时找到了一个字符和 串s的字符 匹配,那么相同子序列长度就在dp[i-1][j-1]的基础上加1

如果 s[i-1] != t[j-1],说明当前在遍历串t 时这个字符和 串s的字符 不匹配,此时相当于 t 要删除元素,若 t 把当前元素t[j-1]删除,那么 dp[i][j] 的数值就是看 s[i-1]t[j-2] 的比较结果,即:dp[i][j] = dp[i][j-1];

3.dp数组初始化

  • 从递推公式可以看出 dp[i][j] 都是依赖于 dp[i-1][j-1] dp[i][j-1] ,所以 dp[0][0]dp[i][0] 是一定要初始化的
vector<vector<int>> dp(s.size() + 1, vector<int>(t.size() + 1, 0));

4.确定遍历顺序

  • 从递推式可以看出 dp[i][j] 依赖于 dp[i-1][j-1]dp[i][j-1],遍历顺序应该是从上到下,从左到右

5.举例推导dp数组

  • dp[i][j] : 表示以下标 i-1 为结尾的字符串 s ,和以下标 j-1 为结尾的字符串 t ,相同子序列的长度为dp[i][j]

那么dp[s.size()][t.size()] = 3,而s.size() = 3,故 st 的子序列,返回 true

注:观察此表格我们可以发现,当串s串t中寻找某一个字符成功时,每一行的最后一个数值都等于当前的 i 值。所以下文代码中有一句 if(dp[i][t.size()] !=i) return false; 说明 串s 中的某一个字符在 串t 中实在无法找不到了,就直接返回false 

(1)动态规划 二维dp 

class Solution {
public:   // 动态规划 二维dpbool isSubsequence(string s, string t) {vector<vector<int>> dp(s.size()+1,vector<int>(t.size()+1,0));for(int i=1;i<=s.size();i++) {for(int j=1;j<=t.size();j++) {if(s[i-1] == t[j-1]) {dp[i][j] = dp[i-1][j-1] + 1;}else dp[i][j] = dp[i][j-1];}if(dp[i][t.size()] !=i) return false;}return dp[s.size()][t.size()] == s.size();}
};
  • 时间复杂度:O(n × m)
  • 空间复杂度:O(n × m)

(2)二维dp 优化空间

class Solution {
public:// 二维dp 优化空间复杂度bool isSubsequence(string s, string t) {vector<vector<int>> dp(2,vector<int>(t.size()+1,0));for(int i=1;i<=s.size();i++) {for(int j=1;j<=t.size();j++) {if(s[i-1] == t[j-1]) dp[i % 2][j] = dp[(i-1)%2][j-1] + 1;else dp[i % 2][j] = dp[i % 2][j-1];}if(dp[i%2][t.size()] !=i) return false;}return dp[s.size() % 2][t.size()] == s.size();}
};
  • 时间复杂度:O(n × m)
  • 空间复杂度:O(m)

(3)一维dp 优化空间

class Solution {
public: // 一维dp 滚动数组 优化空间复杂度bool isSubsequence(string s, string t) {vector<int> dp(t.size()+1,0);for(int i=1;i<=s.size();i++) {int pre = dp[0];for(int j=1;j<=t.size();j++) {int tmp = dp[j];if(s[i-1] == t[j-1]) dp[j] = pre + 1;else dp[j] = dp[j-1];pre = tmp;}if(dp[t.size()] !=i) return false;}return dp[t.size()] == s.size();}
};
  • 时间复杂度:O(n × m)
  • 空间复杂度:O(m)
  • 我思考之后发现内层for循环里的 j 的起始位置可以改一下
class Solution {
public:  bool isSubsequence(string s, string t) {vector<vector<int>> dp(s.size()+1,vector<int>(t.size()+1,0));int tmp=1;for(int i=1;i<=s.size();i++) {bool flag = 0;for(int j=tmp;j<=t.size();j++) {if(s[i-1] == t[j-1]) {dp[i][j] = dp[i-1][j-1] + 1;if(!flag) tmp=j;flag=1;}else dp[i][j] = dp[i][j-1];}if(dp[i][t.size()] !=i) return false;}return dp[s.size()][t.size()] == s.size();}

(二)双指针

(1)while循环写法 

class Solution {
public:bool isSubsequence(string s,string t) {int i=0,j=0;while(i<s.size() && j<t.size()) {if(s[i] == t[j]) {i++;j++;}else j++; }if(i == s.size()) return true;return false;}
};

 (2)for循环写法

class Solution {
public:bool isSubsequence(string s,string t) {if(s.size()==0) return true;int i=0;for(auto c:t) {if(s[i] == c) {i+=1;if(i == s.size()) return true;}}return false;}
};

 参考和推荐文章、视频:

代码随想录 (programmercarl.com)icon-default.png?t=N7T8https://www.programmercarl.com/0392.%E5%88%A4%E6%96%AD%E5%AD%90%E5%BA%8F%E5%88%97.html#%E6%80%9D%E8%B7%AF动态规划,用相似思路解决复杂问题 | LeetCode:392.判断子序列_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1tv4y1B7ym/?spm_id_from=pageDriver&vd_source=a934d7fc6f47698a29dac90a922ba5a3来自代码随想录课堂视频截图:

  • 我写的另一个版本(串 s 用双指针,串 t 也用双指针):
class Solution {
public:bool isSubsequence(string s,string t) {int sl=0,sr=s.size()-1;int tl=0,tr=t.size()-1;int count = 0;if(s.size()==0) return true;while(sl<=sr && tl <= tr) {if(s[sl] == t[tl]) {sl++;tl++;count++;}else tl++;if(tl < tr && s[sr] == t[tr]) {sr--;tr--;count++;}else tr--;}if(s.size() == count) return true;return false;}
};

把串s看作是一个装着 串s 字符的栈 :

class Solution {
public:bool isSubsequence(string s,string t) {if(s.empty()) return true;for(int i=t.size()-1;i>=0;i--) {if(t[i] == s.back()) {s.pop_back();if(s.empty()) return true;};}return false;}
};

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

剖析深度学习中的epoch与batch_size关系、代码

目录 前言1. 定义2. 代码 前言 为了区分深度学习中这两者的定义&#xff0c;详细讲解其关系以及代码 1. 定义 在 PyTorch 中&#xff0c;“epoch”&#xff08;周期&#xff09;和 “batch size”&#xff08;批大小&#xff09;是训练神经网络时的两个重要概念 它们用于控…

【大数据】Kafka 入门简介

Kafka 入门简介 1.什么是 Kafka2.Kafka 的基本概念3.Kafka 分布式架构4.配置单机版 Kafka4.1 下载并解压包4.2 启动 Kafka4.3 创建 Topic4.4 向 Topic 中发送消息4.5 从 Topic 中消费消息 5.实验5.1 实验一&#xff1a;Python 实现生产者消费者5.2 实验二&#xff1a;消费组实现…

光伏电站绝缘阻抗异常排查方法

安科瑞 崔丽洁 概述 01 光伏发电是依托电力电子技术,利用太阳光照将太阳能转化为电能的系统。光伏发电不需要使用化石燃料&#xff0c;减少了发电时产生的污染&#xff0c;并且减少了能源消耗。光伏发电依托政策扶持&#xff0c;快速在国内普及。光伏发电与传统火电发电原理不同…

模糊测试面面观 | 车联网场景模糊测试解决方案

随着国际国内汽车信息安全标准的出台、用户安全意识的不断提高以及针对智能网联汽车安全攻击的不断规模化复杂化和深入&#xff0c;智能网联汽车系统及车联网安全形势严峻。 然而大部分车型在信息安全防护方面水平偏低&#xff0c;车内相关的联网部件及控制部件防护可靠性不高&…

Python接口自动化 —— token登录(详解)

简介 为了验证用户登录情况以及减轻服务器的压力&#xff0c;减少频繁的查询数据库&#xff0c;使服务器更加健壮。有些登录不是用 cookie 来验证的&#xff0c;是用 token 参数来判断是否登录。token 传参有两种一种是放在请求头里&#xff0c;本质上是跟 cookie 是一样的&am…

实时精准 自我防护 | 开源网安RASP平台能力获客户认可!

近日&#xff0c;开源网安收到了一封来自华润数科的感谢信&#xff0c;表达了对开源网安团队在网络安全工作中给予大力支持的衷心感谢。开源网安十分注重客户的需求和信任&#xff0c;客户的满意和认可是开源网安最大的追求。 在助力华润数科网络安全工作开展过程中&#xff0c…

1数据结构的分类,算法效率的度量

一&#xff0c;数据结构的定义和分类 数据结构&#xff1a;数据之间的关系即数据的逻辑结构&#xff0c;因为要存储到计算机里&#xff0c;所以视为将这个数据的逻辑结构映射到存储器里。即数据因为自身的和其他的数据的关系而在计算机内存储的方式。我们就归类了一些类型。 二…

【数据结构】栈(C语言实现)

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 栈 1.栈1.1栈的概念及结构…

2023年中国商业版服务器操作系统市场发展规模分析:未来将保持稳定增长[图]

服务器操作系统一般指的是安装在大型计算机上的操作系统&#xff0c;比如Web服务器、应用服务器和数据库服务器等&#xff0c;是企业IT系统的基础架构平台&#xff0c;也是按应用领域划分的三类操作系统之一。同时服务器操作系统也可以安装在个人电脑上。 服务器操作系统分类 …

荧光EEM平滑教程(去除散射)

说明&#xff1a;本文为drEEM工具箱官网教程《Smoothing EEMs》的笔记。 瑞利散射是一种弹性散射。来自激发源的光子遇到溶液中的分子之后&#xff0c;反弹到各个方向。 最重要的是&#xff0c;瑞利散射&#xff08;的发射波长&#xff09;总是与激发波长完全相等。 因此&…

深入研究Java线程Dump分析:掌握发现和解决多线程问题的关键技巧

1 Thread Dump介绍 1.1 什么是Thread Dump Thread Dump是非常有用的诊断Java应用问题的工具。每一个Java虚拟机都有及时生成所有线程在某一点状态的thread-dump的能力&#xff0c;虽然各个 Java虚拟机打印的thread dump略有不同&#xff0c;但是大多都提供了当前活动线程的快…

关于python环境下的语音转文本,whisper或funASR

因为前阵子&#xff0c;有需求要将语音转为文本再进行下一步操作。感觉这个技术也不算是什么新需求&#xff0c;但是一搜&#xff0c;都是大厂的api&#xff0c;或者是什么什么软件&#xff0c;由于想要免费的&#xff0c;同时也要嵌入在代码中&#xff0c;所以这些都不能用。、…

一个三年女软件测试的成长之路

如果你恰好刚刚进入一家新公司&#xff0c;领导一上来就让你开展自动化测试&#xff0c;作为一名初出茅庐的测试新人&#xff0c;除了手足无措&#xff0c;你只能默默慨叹自己能力尚欠&#xff0c;眼前只会出现一个又一个无从下手的问题&#xff1a; 作为手工测试&#xff0c;…

55 零钱兑换

零钱兑换 题解1 DP另一种解法(更好记) 题解2 递归 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额&#xff0c;返回…

1024程序员节特辑 | ELK+ 用户画像构建个性化推荐引擎,智能实现“千人千面”

专栏集锦&#xff0c;赶紧收藏以备不时之需 Spring Cloud实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏&#xff1a;https://blog.…

《Operating Systems:Three Easy Pieces》 操作系统导论【二】 虚拟化内存

【Operating Systems:Three Easy Pieces 操作系统导论 】 (九) 抽象&#xff1a;地址空间 早期系统 操作系统曾经是一组函数&#xff08;实际上是一个库&#xff09;&#xff0c;在内存中&#xff08;在本例中&#xff0c;从物理地址0开始&#xff09;&#xff0c;然后有一…

程序员各阶段应该掌握的技术与能力

人人都是产品经理 | 产品经理、产品爱好者学习交流平台 (woshipm.com)

华为云云耀云服务器L实例评测|使用clickhouse-benchmark工具对ClickHouse的性能测试

目录 引言 1 ClickHouse简介 2 利用docker安装ClickHouse 2.1 安装Docker 2.2 下载ClickHouse Docker镜像 2.3 创建ClickHouse容器 2.4 访问ClickHouse 3 创建测试表 4 运行 clickhouse-benchmark 5 分析结果 结语 引言 利用华为云的云耀云服务器L实例&#xff0c…

lunux查找占用内存前10的进程

1、使用Top命令查询进程 输入 top 命令&#xff0c;然后按下大写M按照内存MEM排序&#xff0c;按下大写P按照CPU排序。 2、查询占用CPU最高的前10个进程 ps aux|head -1;ps aux|grep -v PID|sort -rn -k 3|head 3、查询占用内存最大的前10个进程 ps aux|head -1;ps aux|grep …

【ELK使用指南 2】常用的 Logstash filter 插件详解(附应用实例)

Logstash filter 一、logstash filter过滤插件的常用模块简介二、grok 正则捕获插件2.1 grok插件的作用2.2 内置正则表达式2.3 自定义正则表达式 三、mutate 数据修改插件3.1 mutate插件的作用3.2 常用的配置选项3.3 mutate插件应用实例 四、multiline 多行合并插件4.1 multili…