代码随想录刷题笔记 Day 58 | 判断子序列 No.392 | 不同的子序列 No.115
文章目录
- Day 58
- 01. 判断子序列(No. 392)
- <1> 题目
- <2> 题解
- <3> 代码
- 02. 不同的子序列(No. 115)
- <1> 题目
- <2> 题解
- <3> 代码
Day 58
01. 判断子序列(No. 392)
题目链接
代码随想录题解
<1> 题目
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"
是"abcde"
的一个子序列,而"aec"
不是)。
进阶:如果有大量输入的 S,称作 S1, S2, … , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
致谢:特别感谢 @pbrother 添加此问题并且创建所有测试用例。
示例 1:
输入:s = “abc”, t = “ahbgdc”
输出:true
示例 2:
输入:s = “axc”, t = “ahbgdc”
输出:false
提示:
0 <= s.length <= 100
0 <= t.length <= 10^4
- 两个字符串都只由小写字符组成。
<2> 题解
如果仅考虑动态规划解法的话,本题是昨天的 最长公共子序列 的简化版本。
子序列的定义为:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
**s 是否是 t 的公共子序列,其实也就代表了 t 和 s 的最长公共子序列是否是 s。**所以本题的动态规划解法就是求得它们两个最长公共子序列的长度,然后判断长度是否等于 s 的长度即可;剩下的步骤和求最长公共子序列的方法就完全相同了。
1. 状态
既然是求最长的公共子序列,那就涉及到 长度,可以分解成如下的子问题:
s 的前一个元素和 t 第一个元素组成的最长公共子序列是多少?
s 的前两个元素和 t 第一个元素组成的最长公共子序列是多少?
s 的前三个元素和 t 第一个元素组成的最长公共子序列是多少?
。。。。。。
一直推到到 s 的前 s.length()
个元素和 t 的前 t.length()
个元素的最长公共子序列的长度为多少。
那这个状态能否转移呢?s 的前 m 个元素和 t 的前 n 个元素的公共子序列的长度,是可以通过 m - 1 和 n - 1 组成的公共子序列的长度推出的。
2. dp 数组的含义
dp 数组设定为一个二维数组 dp[i][j]
表示 s 的钱 i - 1 个元素和 t 的前 j - 1 个元素构成的最长公共子序列的大小。
使用这种后移一位的方式可以减少初始化的复杂程度。
3. 递推公式
对于 s 的第 i 个元素和 t 的第 j 个元素有两种情况:
- 它们是相等的,所以它们可以作为构成子序列的元素存在
- 它们不相等,在这个 长度范围 内需要被剔除
如果它们相等,那
dp[i][j] = dp[i - 1][j - 1] + 1
如果它们不相等,那就是延续前面的子序列在如下三个中取最大:
dp[i - 1][j]
dp[i - 1][j - 1]
dp[i][j - 1]
但因为第二种情况被包含了,所以仅对前两个情况取值即可,也就是
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
4. 初始化
本题中,下层的推导依赖的是左上角的值,所以只需要初始化第一行和第一列即可。
而本题的第一行代表 s 的第 0 个元素(从 1 开始,0 没有意义)和 t 的最长公共子序列,为 0
第一列代表着 t 的第 0 个元素和 s 的最长公共子序列,也是 0
所以均初始化为 0 即可,也就是不需要初始化。
<3> 代码
class Solution {public boolean isSubsequence(String s, String t) {int m = 0;int n = 0;while (m < s.length() && n < t.length()) {if (s.charAt(m) == t.charAt(n)) {m++;n++;} else {n++;}}return m == s.length();}
}
02. 不同的子序列(No. 115)
题目链接
代码随想录题解
<1> 题目
给你两个字符串 s
和 t
,统计并返回在 s
的 子序列 中 t
出现的个数,结果需要对 109 + 7 取模。
示例 1:
输入:s = “rabbbit”, t = “rabbit”
输出:3
解释:
如下所示, 有 3 种可以从 s 中得到 “rabbit” 的方案。
rabbbit
rabbbit
rabbbit
示例 2:
输入:s = “babgbag”, t = “bag”
输出:5
解释:
如下所示, 有 5 种可以从 s 中得到 “bag” 的方案。
babgbag
babgbag
babgbag
babgbag
babgbag
提示:
1 <= s.length, t.length <= 1000
s
和t
由英文字母组成
<2> 题解
1. 状态
本题虽然是困难题,但只要选好转移的状态,解答起来就比较简单了。
本题是要查询 s 中有多少种方法可以得到 t,比如第一个案例 s = “rabbbit”, t = “rabbit”,首先来考虑如何划分这个子问题:既然我去查询 s 有多少种方法可以得到 “rabbit” 比较困难,那能否先去找方法得到 “t” 呢?在之后能否得到 “it” 呢?
好,现在其实子问题的拆分就很明确了
-
s 中得到 “t” 有多少种方法?
-
s 中得到 “it” 有多少种方法?
-
s 中得到 “bit” 有多少种方法?
-
s 中得到 “bbit” 有多少种方法?
。。。。。。
-
s 中得到 “rabbit” 有多少种方法?
这种考虑方式是从后往前去考虑的,其实也可以从前往后去转移。
那这个状态能否转移呢?
比如说现在要组成 BIT 这个序列,现在遍历到粉色的 B 了,现在,只需要知道,它后面的部分 能有几种方法组成 IT 就可以了。
2. dp 数组
本题需要一个二维的 dp 数组:
s = "rabbbit", t = "rabbit"
以上面的测试案例举例,dp[i][j]
表示目标字符串 t 从 i 到 末尾的字段在源字符串 s 从 j 到末尾的范围内有多少种构成的方式。
比如说 dp[3][0]
就是从 0 到 s.length - 1
这个范围内(“rabbbit”)构成 从 3 到 t.length - 1
(“bit”)有几种方式。
3. 递推公式
还是举一个例子比较好理解:
比如说现在要计算这个节点,有多少种构成 BIT 的方式,就是要在这里寻找为 B 的节点
这时候它的前一层,也就是 dp[i + 1][j + 1]
表示从这个节点的后面开始,构成 IT 这个字段的方法
那这个节点构成 BIT 的方法就是 dp[i + 1][j + 1]
种嘛?是不对的,还需要再加上后一个节点构成 BIT 的方法,因为此时得到 BIT 的方法有如下两种:
所以最终得到的递推公式就是这样:
dp[i][j] = dp[i + 1][j + 1] + dp[i][j + 1];
搞清楚递推公式的含义非常关键。
那对于不相等的情况:
比如这里的节点 A,那此时从 A 到末尾构成 BIT 的方法就是它后面那个节点构成 BIT 的方法,得到:
dp[i][j] = dp[i][j + 1];
4. 初始化
因为本题的所有推导都是依赖第一行的,所以要先对第一行进行初始化
if (c1[c1.length - 1] == c2[c2.length - 1]) dp[c1.length - 1][c2.length - 1] = 1;for (int i = c2.length - 2; i >= 0; i--) {if (c2[i] == c1[c1.length - 1]) dp[c1.length - 1][i] = dp[c1.length - 1][i + 1] + 1;else dp[c1.length - 1][i] = dp[c1.length - 1][i + 1];}
先对最后一个元素进行特殊的处理,其他逻辑和前面的相同
<3> 代码
class Solution {public int numDistinct(String s, String t) {if (s.length() <= t.length()) {return s.equals(t) ? 1 : 0;}char[] c1 = t.toCharArray(); // 目标序列char[] c2 = s.toCharArray(); // 提供的序列int[][] dp = new int[c1.length][c2.length];if (c1[c1.length - 1] == c2[c2.length - 1]) dp[c1.length - 1][c2.length - 1] = 1;for (int i = c2.length - 2; i >= 0; i--) {if (c2[i] == c1[c1.length - 1]) dp[c1.length - 1][i] = dp[c1.length - 1][i + 1] + 1;else dp[c1.length - 1][i] = dp[c1.length - 1][i + 1];}for (int i = c1.length - 2; i >= 0; i--) {// 外层遍历要寻找的数组 c2for (int j = c2.length - 2; j >= 0; j--) {if (c1[i] == c2[j]) {dp[i][j] = dp[i + 1][j + 1] + dp[i][j + 1];} else {dp[i][j] = dp[i][j + 1];}}}return dp[0][0];}
}
相关文章:

代码随想录刷题笔记 Day 58 | 判断子序列 No.392 | 不同的子序列 No.115
文章目录 Day 5801. 判断子序列(No. 392)<1> 题目<2> 题解<3> 代码 02. 不同的子序列(No. 115)<1> 题目<2> 题解<3> 代码 Day 58 01. 判断子序列(No. 392) 题目链接…...

【C++11】thread线程库
【C11】thread线程库 目录 【C11】thread线程库thread类的简单介绍函数指针lambda表达式常用在线程中 线程函数参数join与detach利用RAII思想来自动回收线程 原子性操作库(atomic)atomic中的load函数:atomic中对变量进行原子操作的一些函数 CAS(Compare-And-Swap)无…...
【OpenStack】创建系统(VM)实例镜像及实例创建方法
【OpenStack】创建系统(VM)实例镜像及实例创建方法 目录 【OpenStack】创建系统(VM)实例镜像及实例创建方法创建计算镜像加载基本镜像预建镜像手动实例创建cloud-init 搭救使用 `cloud-init` 配置启动实例连接到您的新实例为实例分配 Floating IP创建SSH隧道结论推荐超级课程:…...

灵途科技助力家电智能创新
从智能家电到个护健康,科技无时无刻不在刷新我们对智慧生活的认知,我们也从未像今天这样近距离贴近智慧生活的朴素本质——传感技术。灵途科技专注光电感知技术,持续为智能家电客户提供成熟的全方位感知解决方案。步入发展第八年,…...

Flask python :logging日志功能使用
logging日志的使用 一、了解flask日志1.1、Loggers记录器1.2、Handlers 处理器1.3、Formatters 格式化器 二、使用日志2.1、官网上的一个简单的示例2.2、基本配置2.3、具体使用示例2.4、运行 三、写在最后 一、了解flask日志 日志是一种非常重要的工具,可以帮助开发…...

ethers.js:sign(签名)
Signers 在ethers中Signer是以太坊账户的抽象,可以用来签名消息和交易,如将签名的交易发送到以太坊网络以执行状态更改的操作。 npm install ethers5.4.0// 引入 import { ethers } from ethers签名 this.provider new ethers.providers.Web3Provider(…...

使用npm i进行admin依赖安装的时候出现问题
提示: npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request to https://registry.npm.taobao.org/string-width failed, reason: certificate has expired 切换淘宝源到http或者更换其他国内镜像 npm config set registry http:/…...
【Python笔记-FastAPI】定时任务实现(APScheduler)
目录 一、常见触发器 (一) DateTrigger (二) IntervalTrigger (三) CronTrigger (四) CombinationTrigger 二、代码示例 (一) task_scheduler.py (二) client.py 三、调用说明 (一) 注册任务 (二) 查询任务 (三) 删除任务 实现功能: 定时任务注册、修改、删除、查…...

『Apisix入门篇』从零到一掌握Apache APISIX:架构解析与实战指南
📣读完这篇文章里你能收获到: 🌐 深入Apache APISIX架构: 从Nginx到OpenResty,再到etcd,一站式掌握云原生API网关的构建精髓,领略其层次化设计的魅力。 🔌 核心组件全解析ÿ…...

easyExcel大数据量导出oom
easyExcel大数据量导出 异常信息 com.alibaba.excel.exception.ExcelGenerateException: java.lang.OutOfMemoryError: GC overhead limit exceededat com.alibaba.excel.write.ExcelBuilderImpl.fill(ExcelBuilderImpl.java:84)at com.alibaba.excel.ExcelWriter.fill(Excel…...
react native上传二进制图片、视频的方法
react native获取本地图片我用的react-native-image-picker,但是它只能获取图片路径,以及base64的图片,不能获取到binary二进制形式的。 一开始我是让后端改造接口,把原本传binary的改成了base64,可是,躲得…...

JVM之堆
堆的核心概述 一个JVM实例只存在一个堆内存,堆也是内存管理的核心区域。 Java堆区在JVM启动的时候即被创建,其空间大小也就确定了。是JVM管理的最大一块内存空间。 堆内存的大小是可以调节的。 《JVM虚拟机规范》规定,堆可以处于物理上不连…...

R语言实现——网状 Meta 分析
近来年,网状 Meta 分析相关研究不断涌现,此类研究不但能发表在国内各大核心期刊上,还能在SCI期刊甚至医学4大刊上看到其身影。随手在pubmed上面一搜索,就能得到一万多篇相关文献。俨然成为医学文献研究的“大杀器”! P…...

Java项目:77 springboot母婴商城
作者主页:源码空间codegym 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本课题后端使用SpringBoot Spring Cloud框架,前端采用html,JQuery,JS,DIVCSS技术进行编程&…...

【排序算法】深入解析快速排序(霍尔法三指针法挖坑法优化随机选key中位数法小区间法非递归版本)
文章目录 📝快速排序🌠霍尔法🌉三指针法🌠挖坑法✏️优化快速排序 🌠随机选key🌉三位数取中 🌠小区间选择走插入,可以减少90%左右的递归🌉 快速排序改非递归版本…...

生成微信小程序二维码
首页 -> 统计 可以通过上面二个地方配置,生成小程序的二维码,并且在推广分析里,有详细的分析数据,...

网络编程(1)写一个简单的UDP网络通信程序【回显服务器】,并且实现一个简单的翻译功能
使用 JAVA 自带的api 目录 一、回显服务器 UdpEchoServer 服务器代码 客户端代码 二、翻译功能 UdpDictServer 在UdpDictServer里重写process方法 一、回显服务器 UdpEchoServer /*** 回显服务器* 写一个简单的UDP的客户端/服务器 通信的程序* 这个程序没有啥业务逻辑&am…...

Ansys Speos | Light Expert Group探测器组使用技巧
附件下载 联系工作人员获取附件 概述 相机挡板的设计需要在光路的不同位置同步多个照度图,以尽量减少杂散光。2023R2 Speos提供了一种新的探测器,用于高阶杂散光分析,可以同时对多个探测器进行光线追迹。Light Expert工具可以即时过滤3D视…...

C#学习笔记3:Windows窗口计时器
今日继续我的C#学习之路,今日学习自己制作一个Windows窗口计时器程序: 文章提供源码解释、步骤操作、整体项目工程下载 完成后的效果大致如下:(可选择秒数,有进度条,开始计时按钮等) …...

C语言与sqlite3入门
c语言与sqlite3入门 1 sqlite3数据类型2 sqlite3指令3 sqlite3的sql语法3.1 创建表create3.2 删除表drop3.3 插入数据insert into3.4 查询select from3.5 where子句3.6 修改数据update3.7 删除数据delete3.8 排序Order By3.9 分组GROUP BY3.10 约束 4 c语言执行sqlite34.1 下载…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...

6.9-QT模拟计算器
源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...