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

[Java恶补day9] 438.找到字符串中所有字母异位词

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

示例 1:
输入: s = “cbaebabacd”, p = “abc”
输出: [0,6]
解释:
起始索引等于 0 的子串是 “cba”, 它是 “abc” 的异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的异位词。

示例 2:
输入: s = “abab”, p = “ab”
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 “ab”, 它是 “ab” 的异位词。
起始索引等于 1 的子串是 “ba”, 它是 “ab” 的异位词。
起始索引等于 2 的子串是 “ab”, 它是 “ab” 的异位词。

提示:
1 <= s.length, p.length <= 3 ∗ 10 4 3 * 10^4 3104
s 和 p 仅包含小写字母


知识点:
定长滑动窗口、数组、字符串


解:
这道题有多种实现方式:①定长滑动窗口;②不定长滑动窗口。这里实现的是①定长滑动窗口。
核心思想是:统计字符的出现次数,若s的子串、p中的所有字符的出现次数相同,则当前滑动窗口内的子串是异位词。

首先,获取两个字符串长度,提高后续代码的可读性。

然后,这里定义了两个数组,分别存储字符串s、p中各个字符的出现次数,因此数组大小分别是26,记录所有字母(26个)。使用数组而不是前面题目使用的HashMap,因为要对元素在或不在Map中进行分类讨论,没有数组的操作简单便利。

接着,若字符串s的长度<字符串p的长度,则必不存在异位词,因为无法从s中找到一个比自身还长的子串。

然后,遍历p的每个字符,统计各个字符的出现次数:cntP[p.charAt(i) - 'a']++;

然后,遍历s的每个字符,这里用滑动窗口右边界,控制滑动窗口的内容。这里的核心思路是:
获取当前滑动窗口的左边界,用start表示。因为是定长,所以右边界end-n+1即为左边界的下标。
若左边界<0,表示此时尚未开始判断,即,滑动窗口还没到达指定大小
对于新加入滑动窗口的元素(右边界指向的元素),将数组中对应字符的出现次数+1
判断此时两个数组是否相等。若相等,表明当前滑动窗口内的子串、p中各个字符的出现次数是相同的,因此当前滑动窗口内的子串就是异位词。
更新滑动窗口,对于离开滑动窗口的元素(左边界指向的元素),将数组中对应字符的出现次数-1

时间复杂度:O(∣Σ∣m)。Arrays.equals()时间复杂度是O(∣Σ∣),总共遍历m个元素。
空间复杂度:O(∣Σ∣)。因为两个数组各存储了26个字母
∣Σ∣=包含的字符的数量

class Solution {public List<Integer> findAnagrams(String s, String p) {//核心:定长滑动窗口,统计字母的出现次数,若s、p的字母出现次数相同,则是异位词List<Integer> res = new ArrayList<>();//获取字符串s、p的长度int m = s.length();int n = p.length();//定义数组,存储字符的出现次数(比HashMap的操作更方便)int[] cntS = new int[26];int[] cntP = new int[26];//特殊情况判断,直接返回空列表if (m < n)return res;//统计p的每个字符的出现次数for (int i = 0; i < n; i++) {cntP[p.charAt(i) - 'a']++;}//用滑动窗口右边界控制子串for (int end = 0; end < m; end++) {//获取滑动窗口左边界int start = end - n + 1;//新加入滑动窗口的元素(end指向的元素):出现次数+1cntS[s.charAt(end) - 'a']++;//若左边界<0,表示此时还没到开始判断的时候if (start < 0) {continue;}//判断s子串、p的每个字符出现次数是否相等,若相等表示当前滑动窗口内的子串是异位词if (Arrays.equals(cntS, cntP)) {res.add(start);//将异位词的起始下标加入结果列表}//更新滑动窗口,离开滑动窗口的元素(start指向的元素):出现次数-1cntS[s.charAt(start) - 'a']--;}return res;}
}

参考:
1、灵神解析

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

相关文章:

  • JavaSE核心知识点05实践项目(学生管理系统-控制台版)
  • 前向渲染和延迟渲染
  • 利用仿真软件学习一下RC无源滤波和有源滤波电路
  • 【部署】手搓一个dify可用的rerank模型接口服务
  • VSCode Agent 和 Cursor Agent 系统提示词对比
  • There is a chart instance already initialized on the dom. 柱状图初始化时报前面这个错误如何解决?
  • Python异常处理:优雅地应对程序运行时的“意外”
  • 三轴云台之不完全微分PID控制算法篇
  • 可视化数据大屏适配方案之Scale等比缩放
  • java上机测试错题回顾(3)
  • YOLOv11冻结训练+微调策略实战教程(含效果对比分析)
  • 运维三剑客——grep
  • 【动态规划】子数组系列(二)
  • GEO革命:重新定义AI时代的内容规则
  • 代码随想录算法训练营第五十二天
  • 【笔试训练4】Fibonacci数列|单词搜索|杨辉三角
  • 11、总账管理(GL)数字化转型:财务核心支柱,承担着业务系统复杂多变的重任
  • 测试W5500的第9步_使用SNTP实现网络时间同步
  • 尚硅谷redis7 63-69 redis哨兵监控之理论简介
  • javase JDK 环境变量配置
  • 关于线程死锁的相关知识
  • PortSwigger-01-信息泄露
  • 借助Java,让Cloudflare API为你的网站管理加速
  • 篇章五 数据结构——链表(一)
  • 【CAPL实战】LIN校验和测试
  • 电脑硬盘空间大量被占用怎么办
  • 低功耗双目云台监控设备采用国标控制装置
  • 扩散模型原理详解:从噪声到艺术的神奇之旅
  • win32相关(进程间通信)
  • RISC-V特权模式及切换