代码随想录算法训练营第55天| 392.判断子序列 115.不同的子序列

JAVA代码编写

392.判断子序列

给定字符串 st ,判断 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
  • 两个字符串都只由小写字符组成。

教程:https://programmercarl.com/0392.%E5%88%A4%E6%96%AD%E5%AD%90%E5%BA%8F%E5%88%97.html

方法一:动态规划

思路

五部曲

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

2.确定递归公式

在确定递推公式的时候,首先要考虑如下两种操作,整理如下:

  • if (s[i - 1] == t[j - 1])
    • t中找到了一个字符在s中也出现了
  • if (s[i - 1] != t[j - 1])
    • 相当于t要删除元素,继续匹配

if (s[i - 1] == t[j - 1]),那么dp[i] [j] = dp[i - 1] [j - 1] + 1;,因为找到了一个相同的字符,相同子序列长度自然要在dp[i-1] [j-1]的基础上加1(如果不理解,在回看一下dp[i] [j]的定义

if (s[i - 1] != t[j - 1]),此时相当于t要删除元素,t如果把当前元素t[j - 1]删除,那么dp[i] [j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了,即:dp[i][j] = dp[i][j - 1];

3.数组初始化

初始化均为0

4.遍历顺序

同理从递推公式可以看出dp[i][j]都是依赖于dp[i - 1] [j - 1] 和 dp[i] [j - 1],那么遍历顺序也应该是从上到下,从左到右

5.举个例子

以示例一为例,输入:s = “abc”, t = “ahbgdc”,dp状态转移图如下:

392.判断子序列2

复杂度分析

  • 时间复杂度:O(mn),其中m和n分别表示字符串s和字符串t的长度。
  • 空间复杂度:O(mn)
class Solution {public boolean isSubsequence(String s, String t) {int m = s.length(); int n = t.length();int[][] dp = new int[m+1][n+1];for(int i = 1; i <= m; i++){for(int j = 1; j <= n; j++){if(s.charAt(i-1) == t.charAt(j-1)){dp[i][j] = dp[i-1][j-1] + 1;}else{dp[i][j] = dp[i][j-1];}}}return dp[m][n] == m ? true: false;}
}

方法二:双指针法

思路:初始化两个指针i和j,分别指向s和t的起始位置。

然后,进入循环,循环条件是i小于s的长度且j小于t的长度。在每次循环中,比较s.charAt(i)和t.charAt(j)两个字符是否相等,如果相等,则说明s中的当前字符匹配到了t中的当前字符,此时将i向后移动一位,表示已经匹配成功一个字符。

无论是否匹配成功,都将j向后移动一位,继续比较下一个字符。

最后,循环结束后,判断i是否等于s的长度,如果相等,则说明s中的所有字符都成功匹配到了t的子序列中,返回true,否则返回false。

复杂度分析

  • 时间复杂度:O(min(s.length(), t.length())),其中s.length()和t.length()分别表示字符串s和字符串t的长度。
  • 空间复杂度:O(1)
class Solution {public boolean isSubsequence(String s, String t) {int i = 0, j = 0;while (i < s.length() && j < t.length()) {if (s.charAt(i) == t.charAt(j)) {i++;}j++;}return i == s.length();}public static void main(String[] args) {Solution solution = new Solution();System.out.println(solution.isSubsequence("abc","ahbgdc"));}
}

115.不同的子序列

给你两个字符串 st ,统计并返回在 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
  • st 由英文字母组成

教程:https://programmercarl.com/0115.%E4%B8%8D%E5%90%8C%E7%9A%84%E5%AD%90%E5%BA%8F%E5%88%97.html

方法一:动态规划

思路

五部曲

1.定义数组dp[i] [j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。

2.确定递归公式

这一类问题,基本是要分析两种情况

  • s[i - 1] 与 t[j - 1]相等
  • s[i - 1] 与 t[j - 1] 不相等

当s[i - 1] 与 t[j - 1]相等时,dp[i] [j]可以有两部分组成。

一部分是用s[i - 1]来匹配,那么个数为dp[i - 1] [j - 1]。即不需要考虑当前s子串和t子串的最后一位字母,所以只需要 dp[i-1] [j-1]。

一部分是不用s[i - 1]来匹配,个数为dp[i - 1] [j]。

所以当s[i - 1] 与 t[j - 1]相等时,dp[i] [j] = dp[i - 1] [j - 1] + dp[i - 1] [j];

当s[i - 1] 与 t[j - 1]不相等时,dp[i] [j]只有一部分组成,不用s[i - 1]来匹配(就是模拟在s中删除这个元素),即:dp[i - 1] [j]

所以递推公式为:dp[i] [j] = dp[i - 1] [j];

3.数组初始化

 for (int i = 0; i < s.length() + 1; i++) {dp[i][0] = 1;}

4.遍历顺序

从递推公式dp[i][j] = dp[i - 1] [j - 1] + dp[i - 1] [j]; 和 dp[i] [j] = dp[i - 1] [j]; 中可以看出dp[i] [j]都是根据左上方和正上方推出来的。

5.举个例子

以s:“baegg”,t:"bag"为例,推导dp数组状态如下:

115.不同的子序列

复杂度分析

  • 时间复杂度:O(mn)
  • 空间复杂度:O(mn)
class Solution {public int numDistinct(String s, String t) {int[][] dp = new int[s.length() + 1][t.length() + 1];for (int i = 0; i < s.length() + 1; i++) {dp[i][0] = 1;}for (int i = 1; i < s.length() + 1; i++) {for (int j = 1; j < t.length() + 1; j++) {if (s.charAt(i - 1) == t.charAt(j - 1)) {dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];}else{dp[i][j] = dp[i - 1][j];}}}return dp[s.length()][t.length()];}
}

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

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

相关文章

Linux服务器性能优化小结

文章目录 生产环境监测常见专业名词扫盲服务器平均负载服务器平均负载的定义如何判断平均负载值以及好坏情况如果依据平均负载来判断服务器当前状况系统平均负载和CPU使用率的区别 CPU上下文切换基本概念3种上下文切换进程上下文切换线程上下文切换中断上下文切换 查看上下文切…

Java后端问题排查经验

线上出现问题首先应该做什么&#xff0c;不是解决问题&#xff0c;而是先恢复系统&#xff0c;把损失降到最小&#xff0c;有机会的话保留日志等数据用于后期问题复盘分析。解决问题可以后期慢慢复现排查&#xff0c;而线上用户的体验则不能多耽误一分一秒&#xff0c;任何线上…

word怎么分页?学会这几招,轻松掌握分页功能!

Microsoft Word作为办公文档处理的主力工具&#xff0c;其强大的排版功能为用户提供了丰富的文档编辑体验。其中&#xff0c;分页是一个常用但可能被忽视的重要功能&#xff0c;能够使文档结构更清晰、更易读。本文将向您介绍word怎么分页的三种方法&#xff0c;帮助您更好地掌…

Linux消息队列 msgget()、msgsend()、msgrcv()、msgctl()

一、消息队列 1、消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法 2、每个数据块都被认为是有一个类型&#xff0c;接收者进程接收的数据块可以有不同的类型值 3、消息队列与管道不同的是&#xff0c;消息队列是基于消息的&#xff0c;而管道是基于字节流的&…

目标跟踪 MOT数据集和可视化

目录 MOT15数据集格式简介 gt可视化 本人修改的GT可视化代码&#xff1a; MOT15数据集格式简介 以下内容转自&#xff1a;【目标跟踪】MOT数据集GroundTruth可视化-腾讯云开发者社区-腾讯云 MOT15数据集下载&#xff1a;https://pan.baidu.com/s/1foGrBXvsanW8BI4eybqfWg?…

C语言学习第二十六天(算法的时间复杂度和空间复杂度)

1、算法效率 衡量一个算法的好坏&#xff0c;是从时间和空间两个方面来衡量的&#xff0c;换句话说就是从时间复杂度和空间复杂度来衡量的 这里需要补充一点&#xff1a;时间复杂度是衡量一个算法的运行快慢&#xff0c;空间复杂度是主要衡量一个算法运行所需要的额外空间。 …

【操作系统】实验五 文件系统

实验目的&#xff1a; 1. 掌握文件系统的基本概念和工作机制 2. 掌握文件系统的主要数据结构的实现 3、掌握软件系统实现算法 实验内容&#xff1a; 设计并实现一个虚拟的一级&#xff08;单用户&#xff09;文件系统程序 提供以下操作 1、文件创建/删除接口命令 2、目录创建/删…

Java基于微信小程序的小区车位租赁系统的设计与实现

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 简介技术路线需求分析用户信息管理车位信息管理车位申请管理论坛信息管理 效果图推荐阅读 简介 …

【强化学习-读书笔记】动态规划(策略评估、价值迭代、策略迭代算法)

参考 Reinforcement Learning, Second Edition An Introduction By Richard S. Sutton and Andrew G. Barto动态规划 (Dynamic Programming, DP) 是一类优化方法&#xff0c;在给定一个用马尔可夫决策过程 (MDP) 描述的完备环境模型的情况下&#xff0c;其可以计算最优的策…

优化问题笔记(2)

目录 3. 约束优化问题的全局解3.1 凸优化问题3.2 二次优化问题3.3 无约束二次优化问题3.4 一个典型的二次等式约束二次优化问题 Reference 3. 约束优化问题的全局解 3.1 凸优化问题 局部解成为全局解的一类重要的优化问题是所谓凸优化问题. 我们称优化问题 ( f , D ) (f,\ma…

算法-动态规划

动态规划算法 应用场景-背包问题 介绍 动态规划(Dynamic Programming)算法的核心思想是&#xff1a;将大问题划分为小问题进行解决&#xff0c;从而一步步获取最优解的处理算法动态规划算法与分治算法类似&#xff0c;其基本思想也是将待求解问题分解成若干个子问题&#xff0…

Centos7运行pyppeteer报错Browser closed unexpectedly经验总结【必须手动安装谷歌浏览器以自动安装一些依赖】

参考解决方案&#xff1a;pyppeteer.errors.BrowserError: Browser closed unexpectedly - Stack Overflow ldd ~/.local/share/pyppeteer/local-chromium/588429/chrome-linux/chrome | grep not found 注意&#xff1a;安装google-chrome是为了安装这些缺失的so库&#xff0…

针对这两个趋势,3.0全新新零售商业模式可以采取以下策略:

国内市场确实存在“消费升级”和“消费降级”两个趋势&#xff0c;这是由于不同消费者群体的需求和购买力存在差异。消费升级主要发生在高端市场&#xff0c;消费者愿意为高品质、高价值、高价格的商品和服务付出更多。而消费降级则主要发生在中低端市场&#xff0c;消费者更加…

修改antd表单Form.Item的label颜色的方法

默认的Form.item的标签颜色为黑色&#xff0c;但是如果我是用深色背景&#xff0c;这样的情况下表单就看不清楚label了&#xff0c;就像下面的情况&#xff0c;密码两个字完全看不到&#xff0c;所以想把它改为白色字体&#xff0c;就像上面的账号两个字一样&#xff1a; 所以怎…

随笔记录-springboot_LoggingApplicationListener+LogbackLoggingSystem

环境&#xff1a;springboot-2.3.1 加载日志监听器初始化日志框架 SpringApplication#prepareEnvironment SpringApplicationRunListeners#environmentPrepared EventPublishingRunListener#environmentPrepared SimpleApplicationEventMulticaster#multicastEvent(Applicati…

HarmonyOS ArkTS Tab使用方法(十五)

一&#xff0c;使用方法 Android中Java代码使用fragment进行Tab切换&#xff0c;下面使用HarmonyOS ArkTS 语言实现Tab的使用&#xff0c;代码如下&#xff1a; /** Copyright (c) 2022 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "…

(4)Linux的Redirect 重定向以及打包与压缩

&#x1f4ad; 写在前面 本章仍然是继续对Linux 常用指令进行介绍&#xff0c;将讲解重定向、时间相关的指令、文件查找和打包压缩等指令。我们将初次理解 "Linux下一切皆文件"这一概念&#xff0c;我将通过一个有趣的故事去讲解它。 初识重定向&#xff08;Redire…

如何在本地Docker中部署MinIO服务并实现远程访问管理界面

文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器&#xff0c;可以在各种环境中运行&#xff0c;例如本地、Docker容器、Kubernetes集群等。它兼…

全国巡展“2024人工智能展·世亚智博会”3月上海·4月杭州·6月北京

近年来&#xff0c;我国积极布局人工智能产业&#xff0c;竞跑“未来赛道”。随着各行业、各领域对人工智能需求的日益增长&#xff0c;与实体经济深度融合的新模式不断涌现&#xff0c;形成了具有中国特色的研发体系和应用生态&#xff0c;引领着经济社会各领域从数字化、网络…

web前端项目-影视网站开发

影视网站 本项目主要使用到了 HTML&#xff1b;CSS&#xff1b;JavaScript脚本技术&#xff1b;AJAX无刷新技术&#xff1b;jQuery等技术实现了动态影视网页 运行效果&#xff1a; 一&#xff1a;index.html <!DOCTYPE> <html lang"en"> <head>…