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

力扣经典算法篇-19-判断子序列(双指针法,双指针递归法,批量校验时的进阶解法(预处理+二分查找))

1、题干

给定字符串 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

提示:
0 <= s.length <= 100
0 <= t.length <= 10^4

2、解题

方法一:基础双指针法

使用两个指针,第一个指针指向字符串s的其实位置,第二个指针指向t的起始位置。
分别比较两个指针位置的元素值是否相等,如果相等两个指针同时右移,如果不相等仅t的指针右移即可。
最终查看s的指针有没有滑动到最后的位置,到了最后,说明s已经被全包含了。否则就是没有全包含,即s不是t的子序列。

代码示例:

 public static boolean isSubsequence(String s, String t) {int left1 = 0;int left2 = 0;while (left1 < s.length() && left2 < t.length()) {if (s.charAt(left1) == t.charAt(left2)) {left1++;}left2++;}if (left1 >= s.length()) {return true;}return false;}

方法二:双指针递归法

使用递归+首元素校验和移除的方式。(实际上和双指针的思路一致)
每次都取出两个字符串中的第0个元素进行比较。如果相等,s和t都移除首元素,取各自剩余的部分继续上诉递归处理;如果不相等,s不变,t移除首元素,取各自剩余的部分继续上诉递归处理;
递归终止掉件:s为空,说明s是t的子序列;如果t为空,说明s不是t的子序列。

代码示例:

public static boolean isSubsequence(String s, String t) {if (s.length() == 0) {return true;}if (t.length() == 0) {return false;}if (s.charAt(0) == t.charAt(0)) {s = s.substring(1);t = t.substring(1);return isSubsequence(s, t);}t = t.substring(1);return isSubsequence(s, t);
}

进阶解法:

方法三:(预处理 + 二分查找)

如果有多个s串,都要校验是否是t的子串,可以使用如上的双指针法循环处理。
也可以对t进行预处理,如:取出t中的每一个元素,并记录其存在的位置列表;
之后逐个比较s串,分别校验s的每一个字符是否存在t中的对应的列表;不存在直接判断不是子串,这样可以快速筛掉大量不满足的子串。
当然即使存在了,也要进一步校验是否满足,譬如上一个元素已经对应t的位置3了,下一个元素匹配的位置确是2,这肯定也不行。
只有同时满足存在列表,且当前子串得到的位置比之前的位置更靠后。才能满足是子序列的要求。

代码示例:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class Test24 {private Map<Character, List<Integer>> charIndicesMap;public Test24(String t) {charIndicesMap = new HashMap<>();for (int i = 0; i < t.length(); i++) {char c = t.charAt(i);charIndicesMap.putIfAbsent(c, new ArrayList<>());charIndicesMap.get(c).add(i);}}public boolean isSubsequence(String s) {int prevIndex = -1; // 上一次匹配的位置for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);List<Integer> indices = charIndicesMap.get(c);if (indices == null) return false;// 使用二分查找找第一个大于prevIndex的值int pos = binarySearchGreaterThan(indices, prevIndex);if (pos == -1) return false;prevIndex = pos;}return true;}// 在有序列表中找第一个大于target的数private int binarySearchGreaterThan(List<Integer> list, int target) {int left = 0, right = list.size() - 1;int res = -1;while (left <= right) {int mid = left + (right - left) / 2;if (list.get(mid) > target) {res = list.get(mid);right = mid - 1;} else {left = mid + 1;}}return res;}public static void main(String[] args) {Test24 checker = new Test24("ahbgdc");System.out.println(checker.isSubsequence("abc")); // trueSystem.out.println(checker.isSubsequence("aec")); // falseSystem.out.println(checker.isSubsequence("bdc")); // trueSystem.out.println(checker.isSubsequence("abz")); // false}
}

向阳出发,Dare To Be!!!

http://www.xdnf.cn/news/15323.html

相关文章:

  • AI交互中的礼貌用语:“谢谢“的效用与代价分析
  • Sping AI Alibaba
  • 【unitrix】 5.1 第二套类型级二进制数基本结构体(types2.rs)
  • Sqlmap工具下载及使用
  • 【算法】贪心算法入门
  • 算法学习笔记:19.牛顿迭代法——从原理到实战,涵盖 LeetCode 与考研 408 例题
  • 【SCI 4区推荐】《Journal of Visual Communication and Image Representation》
  • 代码随想录|图论|14有向图的完全可达性
  • 集训Demo1
  • CVPR2025 Mamba系列
  • JAVA--双亲委派机制
  • 维基艺术图片: python + scrapy 爬取图片
  • Linux系统中部署Redis详解
  • 算法练习6-大数乘法(高精度乘法)
  • RocketMQ-
  • 【字符串移位包含问题】2022-8-7
  • Opencv---深度学习开发
  • 单细胞入门(1)——介绍
  • 电商订单数据分析全流程:从数据处理到可视化洞察
  • 【PTA数据结构 | C语言版】车厢重排
  • Geant4 安装---Ubuntu
  • 【深度剖析】致力“四个最”的君乐宝数字化转型(下篇:转型成效5-打造数字化生存能力探索可持续发展路径)
  • 26. 删除有序数组中的重复项
  • 【MySQL笔记】事务的ACID特性与隔离级别
  • 详细理解向量叉积
  • 二分搜索 (左程云)
  • 【C/C++】编译期计算能力概述
  • uniapp弹出手机键盘,布局被顶飞,导致页面混乱问题
  • 使用Pycharm集成开发工具远程调试部署在虚拟机上的flask项目:超级详细的完整指南
  • Rust Web 全栈开发(六):在 Web 项目中使用 MySQL 数据库