Java【手撕滑动窗口】LeetCode 438. “字符串中所有异位词“, 图文详解思路分析 + 代码

文章目录

  • 前言
  • 一、字符串中所有异位词
    • 1, 题目
    • 2, 思路分析
      • 2.1, 引入哈希表找出异位词
      • 2.2, 引入变量记录"有效字符的个数"
      • 2.3, left 右移维护窗口
      • 2.4, 总结核心步骤
    • 3, 代码


前言

各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你:
📕 JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统等
📗 Java数据结构: 顺序表, 链表, 堆, 二叉树, 二叉搜索树, 哈希表等
📘 JavaEE初阶: 多线程, 网络编程, TCP/IP协议, HTTP协议, Tomcat, Servlet, Linux, JVM等(正在持续更新)

一、字符串中所有异位词

1, 题目

OJ链接

以示例1为例, 给定字符串 s 为 : "cbaebabacd", 字符串 p 为"abc", "abc""cba", "acb", "bca" 等是异位词, 要求在 s 中找到 p 的所有异位词, 意思就是在 s 中找到连续的子区间, 这段区间是 p 的异位词

  • 关于异位词
    我们只需要 s 的连续子区间内找到包含 ‘a’, ‘b’, ‘c’ 的三个字符即可, 不一定非要是"abc", 这点很重要 ! !

一般来说, 如果我们研究的对象是 “连续的区间” 就可以考虑滑动窗口

滑动窗口其实就是"同向双指针", 滑动窗口的特点是, 前后两个指针不会回退, 并且窗口总是向前滑动, 窗口不是固定大小的, 可能边长也可能变短, 如果你在分析题目的时候发现了这些特征, 那就基本是滑动窗口的解法了


2, 思路分析

首先可以确定的是, 一定要有两个哈希表, 一个哈希表来记录字符串 p 中的字符出现了几次, 一个哈希表用来记录在字符串 s 的子区间中的字符出现了几次

基本思路 :

  • 1, 为了方便, 可以将字符串 s 和 p 分别转化为字符数组 : arrayS 和 arrayP
  • 2, 定义两个哈希表, hashP 和 hashWindow
  • 3, 定义 left 和 right 指针, 初始位置都从0开始, left 用于标记子序列的左边界, right 用于标记子序列的右边界

题目中说明了字符都是 ‘a’ ~ ‘z’ 的小写字符, 为了进一步提高效率, 可以直接使用长度为 26 的 int[] 数组来模拟哈希表, 用字符来映射出 0~25下标, 例如字符 ‘a’ 在哈希表中的下标就是 ‘a’ - ‘a’ = 0, 字符 ‘c’ 在哈希表中的下标就是 ‘c’ - ‘a’ = 2


2.1, 引入哈希表找出异位词

首先要把 arrayP (字符串 p 的字符数组) 中的字符在哈希表中映射, 出现几次就把哈希表中对应下标的值设为几

然后在 arrayS (字符串 s 的字符数组) 中找到的字符也在哈希表中映射, 同上

要注意, 使用者两个哈希表的目的是记录 “字符出现的次数”, 而不是"字符出现的个数"
例如要找 “bbc” 的异位词, ‘b’ 在哈希表中出现两次, ‘c’ 在哈希表中出现一次, 重点是字符出现的次数而不是个数

由于我们要找的子区间长度是和字符串 p 长度一致的, 所以要让 right 和 left 维护子区间的长度

在这里插入图片描述

此时 right 和 left 维护的子区间的长度和 arrayP 长度一致, 并且我们发现两个哈希表中的所记录的 “字符出现的次数” 是一致的, 那就可以认为我们找到了一个异位词

这里可以做优化 ! ! 如何判断两个哈希表中的所记录的 “字符出现的次数” 是一致的?

如果每次在 arrayS 中找到长度为 3 的子区间都遍历两个 hash 表, 是比较浪费时间的, 我们可以引入一个变量 count 用于记录"有效字符的个数"


2.2, 引入变量记录"有效字符的个数"

首先图解一下什么情况下, 字符为有效, 什么情况下不有效

注意观察不同示例下的 arrayS 和 arrayP
在这里插入图片描述
综上所述, right 每遍历到一个新的字符时, 就可以对比两个哈希表中的值来判断该字符是否有效

  • hashWindow[arrayS[right] - 'a'] <= hashP[arrayS[right] - 'a'] 时, 为有效字符, 此时可以让变量 count++
  • count == arrayP 时, 说明 right 和 left 维护的子区间的字符全都是有效字符, 即全都是 arrayP 中的字符, 此时可以把 left 加入到 list 中, 作为返回结果

2.3, left 右移维护窗口

上面说过, 假设我们要找的异位词的长度为 3 , 那么 right 和 left 维护的子区间(窗口)的长度就不能大于 3, 当窗口长度为 3 时, 判断 count 的值以判断是否为异位词

所以当窗口长度大于 3 时, 需要让 left 右移来实现"滑动窗口", 这一步有值得注意的细节在这里插入图片描述

本题的窗口在"滑动:过程中长度总是为 arrayP.length, 在"滑动窗口"中属于窗口长度不变的类型


2.4, 总结核心步骤

  • 1, right 指向新字符时, 在 hashWindow 中更新该字符出现的次数
  • 2, 判断 right 指向的字符是否为有效字符, 如果是, 令 count++
  • 3, 判断窗口大小是否大于 arrayP.length, 如果是, 令 left–
  • 4, 在 left-- 之前判断当前 left 指向的字符是否为有效字符, 如果是, 则 count- -
  • 5, 判断 count 是否和 arrayP.length 相等, 如果是, 令当前 left 存入 list 中

3, 代码

	public List<Integer> findAnagrams(String s, String p) {List<Integer> ret = new ArrayList<>();char[] arrayP = p.toCharArray();char[] arrayS = s.toCharArray();int[] hashP = new int[26];int[] hashWindow = new int[26];for(char ch : arrayP) {hashP[ch-'a']++;}int left = 0;int right = 0;int count = 0;// 有效字符个数while(right < arrayS.length) {hashWindow[arrayS[right] - 'a']++;if(hashWindow[arrayS[right] - 'a'] <= hashP[arrayS[right] - 'a']) {count++;}if(right - left + 1 > arrayP.length) {// left 右移之前要先判断是否为有效字符if(hashWindow[arrayS[left] - 'a'] <= hashP[arrayS[left] - 'a']) {// 说明是有效字符count--;}// hash表里面的该字符也要自减一次hashWindow[arrayS[left] - 'a']--;left++;}if(count == arrayP.length) {ret.add(left);}right++;}return ret;}

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

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

相关文章

弹性盒子的使用

一、定义 弹性盒子是一种用于按照布局元素的一维布局方法&#xff0c;它可以简便、完整、响应式地实现各种页面布局。 容器中存在两条轴&#xff0c;主轴和交叉轴(相当于我们坐标轴的x轴和y轴)。我们可以通过flex-direction来决定主轴的方向。 主轴&#xff08;main axis&am…

运维自动化与Cobbler服务部署

运维自动化与Cobbler服务部署 一.Cobbler简介 1.1.简介 Cobbler是一款Linux生态的自动化运维工具&#xff0c;基于Python2开发&#xff0c;用于自动化批量部署安装操作系 统&#xff1b;其提供基于CLI的管理方式和WEB配置界面&#xff0c;其中WEB配置界面是基于Python2和Djang…

Linux查看是虚拟机还是物理机

第一种方式&#xff1a;dmesg命令 [roottest ~]# dmesg | grep -i hypervisor [ 0.000000] Hypervisor detected: VMware [ 0.001000] TSC freq read from hypervisor : 2903.999 MHz [ 6.311621] [drm] Max dedicated hypervisor surface memory is 0 kiB第二种方式…

K8S Nginx Ingress实现金丝雀发布

通过给 Ingress 资源指定 Nginx Ingress 所支持的 annotation 可实现金丝雀发布。 需给服务创建2个 Ingress&#xff0c;其中1个常规 Ingress&#xff0c;另1个为带 nginx.ingress.kubernetes.io/canary: "true" 固定的 annotation 的 Ingress&#xff0c;称为 Cana…

美团 Flink 资源调度优化实践

摘要&#xff1a;本文整理自美团数据平台计算引擎组工程师冯斐&#xff0c;在 Flink Forward Asia 2022 生产实践专场的分享。本篇内容主要分为四个部分&#xff1a; 相关背景和问题解决思路分析资源调度优化实践后续规划 点击查看原文视频 & 演讲PPT 一、相关背景和问题 在…

【Spring Boot】使用XML配置文件实现数据库操作(一)

使用XML配置文件实现数据库操作&#xff08;一&#xff09; 1.SQL映射文件 SQL映射文件就是我们通常说的mapper.xml配置文件&#xff0c;主要实现SQL语句的配置和映射&#xff0c;同时实现Java的POJO对象与数据库中的表和字段进行映射关联的功能。 1.1 mapper.xml的结构 下…

100天精通Python(可视化篇)——第99天:Pyecharts绘制多种炫酷K线图参数说明+代码实战

文章目录 专栏导读一、K线图介绍1. 说明2. 应用场景 二、配置说明三、K线图实战1. 普通k线图2. 添加辅助线3. k线图鼠标缩放4. 添加数据缩放滑块5. K线周期图表 书籍推荐 专栏导读 &#x1f525;&#x1f525;本文已收录于《100天精通Python从入门到就业》&#xff1a;本专栏专…

Unity中Shader的混合模式Blend

文章目录 前言一、混合的作用就是实现各种半透明效果二、混合操作三、在 Shader 中暴露两个属性 来调节 混合的效果 前言 Unity中Shader的混合模式Blend 一、混合的作用就是实现各种半透明效果 这里用PS里的混合作为例子 没选择混合效果前&#xff0c;显示的效果是这样 选择…

基于 Zookeeper 实现服务注册和服务发现

文章目录 前言声明前置知识服务注册和发现Zookeeper 工作原理实现过程注册中心服务注册服务发现 总结 前言 无论是采用SOA还是微服务架构&#xff0c;都需要使用服务注册和服务发现组件。我刚开始接触 Dubbo 时一直对服务注册/发现以及 Zookeeper 的作用感到困惑&#xff0c;现…

React 18 对 state 进行保留和重置

参考文章 对 state 进行保留和重置 各个组件的 state 是各自独立的。根据组件在 UI 树中的位置&#xff0c;React 可以跟踪哪些 state 属于哪个组件。可以控制在重新渲染过程中何时对 state 进行保留和重置。 UI 树 浏览器使用许多树形结构来为 UI 建立模型。DOM 用于表示 …

解决Linux Ubuntu上安装RabbitMQ服务后的公网远程访问问题,借助cpolar内网穿透技术

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…

软件产品确认测试鉴定测试

软件产品确认测试 确认测试也称鉴定测试&#xff0c;即验证软件的功能、性能及其它特性是否与用户的要求一致。软件确认测试是在模拟的环境下&#xff0c;验证软件是否满足需求规格说明书列出的需求。为此&#xff0c;需要首先制定测试计划&#xff0c;规定要做测试的种类&…

Pinely Round 2 (Div. 1 + Div. 2) F. Divide, XOR, and Conquer(区间dp)

题目 给定长为n(n<1e4)的数组&#xff0c;第i个数为ai(0<ai<2的60次方) 初始时&#xff0c;区间为[1,n]&#xff0c;也即l1&#xff0c;rn&#xff0c; 你可以在[l,r)中指定一个k&#xff0c;将区间分成左半边[l,k]、右半边[k1,r] 1. 如果左半边异或和与异或和的异…

分类预测 | MATLAB实现GRNN广义回归神经网络多特征分类预测

分类预测 | MATLAB实现GRNN广义回归神经网络多特征分类预测 目录 分类预测 | MATLAB实现GRNN广义回归神经网络多特征分类预测分类效果基本介绍模型描述预测过程程序设计参考资料分类效果 基本介绍 MATLAB实现GRNN广义回归神经网络多特

自建音乐服务器Navidrome之一

这里写自定义目录标题 1.1 官方网站 2. Navidrome 简介2.1 简介2.2 特性 3. 准备工作4. 视频教程5. 界面演示5.1 初始化页5.2 专辑页 前言 之前给大家介绍过 Koel 音频流服务&#xff0c;就是为了解决大家的这个问题&#xff1a;下载下来的音乐&#xff0c;只能在本机欣赏&…

「Redis」1. 数据类型的底层实现

前言&#xff1a;在这篇博文中&#xff0c;我们将简单总结在面试中怎么回答Redis数据类型的底层实现。 因为面试时间就那么点&#xff0c;言简意赅的描述自己会的知识显得尤为重要‼️ 文章目录 0.1. String 的底层实现原理0.2. 列表的底层实现原理0.3. 字典的底层实现原理0.4.…

​放弃数据库,改用Kafka!

长期以来&#xff0c;数据库一直充当着记录系统&#xff0c;它们以可靠且持久的方式存储和管理关键数据&#xff0c;也赢得了大多数公司的信赖。 但时代在变。许多新兴趋势正在影响当今数据的存储和管理方式&#xff0c;不得不让一些技术决策者们重新考虑数据存储究竟还有哪些…

敏感接口权限校验

前端校验 &#xff08;从前端或者从token里面拿一下&#xff09;&#xff0c;看一下用户有没有这个页面的权限&#xff08;但是一般不用&#xff0c;因为nodejs也可以写后端&#xff0c;但是放到前端去校验不安全&#xff09; 后端校验 需要梳理敏感数据接口&#xff0c;将这…

重写 UGUI

重写Button using UnityEngine; using UnityEngine.UI; public class MyButton : Button {[SerializeField] private int _newNumber; }using UnityEditor;//编辑器类在UnityEditor命名空间下。所以当使用C#脚本时&#xff0c;你需要在脚本前面加上 "using UnityEditor&q…

Hive-安装与配置(1)

&#x1f947;&#x1f947;【大数据学习记录篇】-持续更新中~&#x1f947;&#x1f947; 个人主页&#xff1a;beixi 本文章收录于专栏&#xff08;点击传送&#xff09;&#xff1a;【大数据学习】 &#x1f493;&#x1f493;持续更新中&#xff0c;感谢各位前辈朋友们支持…