代码随想录刷题笔记 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 <= 1000 <= 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 <= 1000s和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 下载…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
