【优选算法 — 滑动窗口】串联所有单词的子串 最小覆盖子串

    

 


   串联所有单词的子串   


 串联所有单词的子串


题目描述 


题目解析


 


   算法原理   


 

以示例一为例,一定要记得,words中的每一个字符串长度相同,所以我们可以根据 words 中的每一个字符串的长度length,将 s 这个字符串以 length 个为一组来进行划分。

 通过这样的转换,就变成了上一篇优选算法的问题:“找出字符串中所有字母异位词”

 

所以这道题的示例一:

    解法:滑动窗口 + 哈希表    


    两道题不同之处: 


   1. 哈希表    


在438题中,我们是通过数组来模拟哈希表,因为哈希表中的每一个元素 key 是一个个字符;

但是在这题是一个个字符串,映射关系是 HashMap<String, int >,表示字符串及出现次数 ;


    2. left 和 right 指针的移动    


刚开始,我们的left 和 right 两个指针,都指向 s 字符串的第一个元素:

 

但是我们在每次入窗口操作时,都要把三个字符组成的字符串划入哈希表中,所以 left,right 移动的步长,是 words 中字符串元素的长度。

在这题中,我们移动 right ,让第二个字符串进入哈希表:


   3. 滑动窗口的执行次数   


因为我们是把三个字符 看作是一个字符,所以划分方法有很多种,如下面的这三种:

  • 因此滑动窗口的次数,就是能列举出来的上图的三种情况;
  • 因为上面三种情况,分别以 s 的第一,第二,第三个字符为起点,把长度3的字符串看成一个字符;
  • 那接下来就是以第四个字符为起点,那这种情况就变回了上面的第一种划分方法,只是少了第一个字符串 "bar" ;
  • 同理,后面再以第五,第六,第七个 .......s 字符串的字符为起点,结果都能合并为上面三种划分情况

   编写代码    


定义哈希表 hash1,用来保存 wors 中所有单词(字符串元素)的频次 

把 words 的每一个字符串元素存入 hash1

滑动窗口的执行次数(外层 for 循环)


完善滑动窗口的主逻辑;


left 和 right 指针不是从0开始,而是从 i 开始,如果 left 和 right 从0开始,就会重新遍历很多已经遍历过的字符串(内层 for 循环);

count 用来记录有效字符串的个数:


注意,求数组长度和字符串长度,分别使用的是 length 和 length()


接下来有一个小细节:


所以对于上面的这两种情况,right 指针能到的极限位置就是上面两种情况 right 指向的位置,只要 right 到达这个位置,就不能再往后移动了,所以我们修改一下代码:


定义一个哈希表 hash2,保存窗口内所有单词的频次;


进窗口,维护 count;此时,input 存的字符串,就是要进窗口的字符串:


进窗口 


方法一:

执行用时


方法二

执行用时


进完窗口,要看一下 key 为 input 的哈希元素,如果 hash2 的 val 是否小于 hash1 ,则 count++


  • 但是有一个问题,如果在 hash1 中并没有 key 为 input 的元素,则会报错;
  • 因为调用哈希表中的 get(key),如果对应的 val 为0,则代表不存在这个映射,get() 此时返回 null
  • 因此我们修改一下代码(如果 hash1 中有 key 为 input 的元素,返回该元素 val,否则返回0;)


判断是否需要出窗口:


注意 m = words.length,表示单词的个数,len 表示 words 中的单词长度。len*m 表示窗口长度。

(如果 right - left +1  > len*m,就出窗口,注意不是一个word 的长度,而是 words所有字符之和)


在 if 中,进行出窗口:


要在出窗口之前,维护 count,和上一次维护 count 的原理一样:


更新结果 

完整代码


    最小覆盖子串   


 最小覆盖子串


 

   题目解析    

    算法原理     


每次以一个有效字符开始找,直到找完所有符合条件的字符,返回这个子串,然后开始以下一个有效字符为起点开始遍历:

我们用 hash1 存放 t 字符串的字符,hash1的每一个元素 key 为字符,val 为字符出现次数;

再以 hash2 存放 s 字符串的字符,只要遍历到 s 中的字符str,在hash2.get(str)<hash1.get(str),则是有效字符,凑齐所有 t 中所有字符的字符串,就是一个有效字符串;


   进出窗口的原理    

那么为了不失一般性,我们以上图的抽象例子,来讲解 left 和 right 组成有效字符串后 ,left 和 right 会出现的情况:

left 向后移动一步 ,从字符 str1走到 str2:


   情况一: left 删除的是无效字符   


  • 如果 str1 字符在 t 中也有,但是 hash2.get(str1)>hash1.get(str1),则说明 str1并不是一个有效的字符,所以 right 不动;
  • right 不动,是因为新的 left 和 right 组成的字符串依旧是有效的字符串,left 删除的是一个无效字符
  • 但是 right 一回退,则一定会导致有效字符串变成无效字符串,因为 right 只有在 left 和 right 构成有效字符串才会停下来;

   情况二:left 删除的是一个有效字符   


  •  left ++,如果导致新 left 和 right 组成的字符串从有效字符串,变成无效字符串;
  • 则因为 left 删除的字符,导致 hash2.get(str1)<hash1.get(str1) ;
  • 对于这种情况,只能让 left 停止 ++操作,让 right 往后 ++;
  • right 向后遍历,直到 right 遍历到 str1 的时候停止 ++,这时候 left 和 right 就是下一个有效字符串;

通过两种情况,发现 left 和 right 是同向移动的,所以使用滑动窗口解决该题;


   解法:滑动窗口 + 哈希表 (how 很重要,但是 why 最重要)  


  • left = 0, right = 0;
  • 进窗口(right ++,对应 key 的字符的 val++);
  • 判断是否出窗口(check(hash1,hash2)==true,说明窗口合法,才出窗口,这和前面的题目都不一样)
  • 根据问题,找到合适的位置更新结果(更新起始位置 left 和最短长度,这样就能还原最短子串)
  • (程序执行到这里,窗口都是合法的,因此更新结果的步骤放到判断和出窗口之间); 
  • 出窗口(left 出窗口,直到上面判断中的 check(hash1,hash2)==false);

   优化判断条件   


上面的判断步骤,在每次循环时,都会对 hash1 和 hash2 进行判断,但是每次判断都需要遍历一次 hash1 和 hash2,这样太耗费时间了,我们可以优化判断这一过程;

我们可以定义一个变量 count,标记有效字符的种类(之前标记的都是有效字符的个数);

因为在串联所有单词的子串中,对于 hash1 和 hash2 中,元素的 val 必须是一 一 对应的,hash1的key对应的val有多少个,hash2就必须有多少个;


但是这道题:

所以,只要 left 和 right 组成的字符串对应的 hash2,每个 key 的 val 都大于等于 hash1,那么就是一个合法窗口,所以 count 标记的是有效字符的种类

count 只看当前字符是不是有效字符(当前字符val:hash2 >= hash1),而不看当前字符出现的次数,因此统计的是种类,为什么是种类,刚才已经解释过了,因为字符val不是一 一对应的关系


  • 进窗口之后,维护 count:只有两个字符出现的次数相等,count 才+1,否则会统计重复的;
  • 出窗口之前,维护count:只有两个字符出现的次数相等,count 才-1,否则会统计重复的;
  • (因为 count 的出现,只服务于能成为有效字符串的指针移动,出现次数大于的时候,不影响有效字符串;出现次数小于的时候,会从有效字符串变成无效字符串;所以只有等于的时候,才+1)
  • 判断条件(只有 count = 哈希表的元素种类hash.size() 时,而不是等于字符数量;count只有凑齐所有的有效字符,才更新结果,而不关系如何成为有效字符,出现次数多了也不算有效字符

 编写代码 


这题可以用字符模拟哈希表(使用容器增删查改为O(1),但是消耗还是很大的)

统计字符串 t 中字符的频次

 因为



    

 

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

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

相关文章

WEB攻防-通用漏洞SQL注入sqlmapOracleMongodbDB2等

SQL注入课程体系&#xff1a; 1、数据库注入-access mysql mssql oracle mongodb postgresql 2、数据类型注入-数字型 字符型 搜索型 加密型&#xff08;base64 json等&#xff09; 3、提交方式注入-get post cookie http头等 4、查询方式注入-查询 增加 删除 更新 堆叠等 …

7.揭秘C语言输入输出内幕:printf与scanf的深度剖析

揭秘C语言输入输出内幕&#xff1a;printf与scanf的深度剖析 C语言往期系列文章目录 往期回顾&#xff1a; VS 2022 社区版C语言的安装教程&#xff0c;不要再卡在下载0B/s啦C语言入门&#xff1a;解锁基础概念&#xff0c;动手实现首个C程序C语言概念之旅&#xff1a;解锁关…

SHELL(4)脚本与用户交互以及if条件判断

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

Springboot集成ElasticSearch实现minio文件内容全文检索

一、docker安装Elasticsearch &#xff08;1&#xff09;springboot和Elasticsearch的版本对应关系如下&#xff0c;请看版本对应&#xff1a; 注意安装对应版本&#xff0c;否则可能会出现一些未知的错误。 &#xff08;2&#xff09;拉取镜像 docker pull elasticsearch:7…

使用chrome 访问虚拟机Apache2 的默认页面,出现了ERR_ADDRESS_UNREACHABLE这个鸟问题

本地环境 主机MacOs Sequoia 15.1虚拟机Parallels Desktop 20 for Mac Pro Edition 版本 20.0.1 (55659)虚拟机-操作系统Ubuntu 22.04 服务器版本 最小安装 开发环境 编辑器编译器调试工具数据库http服务web开发防火墙Vim9Gcc13Gdb14Mysql8Apache2Php8.3Iptables 第一坑 数…

定时器的小应用

第一个项目 第一步&#xff0c;RCC开启时钟&#xff0c;这个基本上每个代码都是第一步&#xff0c;不用多想&#xff0c;在这里打开时钟后&#xff0c;定时器的基准时钟和整个外设的工作时钟就都会同时打开了 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);第二步&…

【工控】线扫相机小结 第三篇

海康软件更新 目前使用的是 MVS_STD_4.3.2_240705.exe &#xff0c;最新的已经到4.4了。 一个大的变动 在上一篇中我们提到一个问题&#xff1a; 需要注意的是&#xff0c;我们必须先设置 TriggerSelector 是 “FrameBurstStart” 还是 “LineStart” 再设置TriggerMode 是 …

零基础利用实战项目学会Pytorch

目录 pytorch简介 1.线性回归 2.数据类型 2.1数据类型检验 2.2Dimension0/Rank0 2.3 Dim1/Rank1 2.4 Dim2/Rank2 3.一些方法 4.Pytorch完成分类任务 4.1模型参数 4.2 前向传播 4.3训练以及验证 4.4 三行搞定&#xff01; 4.5 准确率 5、Pytorch完成回归任务 5.…

【#IEEE独立出版、EI稳定检索##高录用 快见刊 稳检索#】2024健康大数据与智能医疗国际会议(ICHIH 2024,12月13-15日)

#IEEE独立出版、EI稳定检索# #往届快至会后3-4个月检索# #高录用 快见刊 稳检索# 2024健康大数据与智能医疗国际会议&#xff08;ICHIH 2024&#xff09; 2024 International Conference on Health Big Data and Intelligent Healthcare 重要信息 大会官网&#xff1a;ww…

vue3中ElementPlus引入下载icon图标不显示透明问题解决教程方法

问题&#xff1a;今天用vue3开发&#xff0c;使用ElementPlus图标引入了但是不显示&#xff0c;是空白透明 解决&#xff1a; 1、在main.js中引入element-plus/icons-vue图标库 import * as ElIcons from element-plus/icons-vue; // 引入图标库 2、注册所有图标 // 注册所有…

1+X应急响应(网络)系统加固:

系统加固&#xff1a; 数据库的重要性&#xff1a; 数据库面临的风险&#xff1a; 数据库加固&#xff1a; 业务系统加固&#xff1a; 安全设备加固&#xff1a; 网络设备加固&#xff1a;

Web导出Excel表格

背景&#xff1a; 1. 后端主导实现 流程&#xff1a;前端调用到导出excel接口 -> 后端返回excel文件流 -> 浏览器会识别并自动下载 场景&#xff1a;大部分场景都有后端来做 2. 前端主导实现 流程&#xff1a;前端获取要导出的数据 -> 常规数据用插件处理成一个e…

【Linux】Github 仓库克隆速度慢/无法克隆的一种解决方法,利用 Gitee 克隆 Github 仓库

Github 经常由于 DNS 域名污染以及其他因素克隆不顺利。 一种办法是修改 hosts sudo gedit /etc/hosts加上一行 XXX.XXX.XXX.XXX github.comXXX 位置的 IP 可以通过网站查询 IP/服务器github.com的信息-站长工具 这种方法比较适合本身可以克隆&#xff0c;但是速度很慢的…

理解反射,学会反射:撬开私有性质(private)的属性与方法

看到这句话的时候证明&#xff1a;此刻你我都在努力 加油陌生人 个人主页&#xff1a;Gu Gu Study专栏&#xff1a;用Java学习数据结构系列喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹喜欢的话可以点个赞谢谢了。作者&#xff1a;小…

函数式编程(4) 纯函数

纯函数&#xff1a;每次调用时结果总是一样 这个函数不纯&#xff1a;返回的值有变化 这个函数不纯:因为使用了全局变量minAge 要让它变成纯函数需要 纯函数的好处 immutability/不变性 如果创建了一个对象 js中的const阻止了重新分配一个对象给book, 而并不能阻止给更改其titl…

【Golang】——Gin 框架中间件详解:从基础到实战

中间件是 Web 应用开发中常见的功能模块&#xff0c;Gin 框架支持自定义和使用内置的中间件&#xff0c;让你在请求到达路由处理函数前进行一系列预处理操作。这篇博客将涵盖中间件的概念、内置中间件的用法、如何编写自定义中间件&#xff0c;以及在实际应用中的一些最佳实践。…

Python爬虫知识体系-----requests-----持续更新

数据科学、数据分析、人工智能必备知识汇总-----Python爬虫-----持续更新&#xff1a;https://blog.csdn.net/grd_java/article/details/140574349 文章目录 一、安装和基本使用1. 安装2. 基本使用3. response常用属性 二、get请求三、post请求四、代理 一、安装和基本使用 1.…

【B+树特点】

B树的特点 B树是B树的一种变体&#xff0c;广泛用于数据库系统和文件系统中&#xff0c;特别是在索引结构中。B树在B树的基础上进行了优化&#xff0c;主要在数据存储和查询效率上有所提升。以下是B树的主要特点&#xff1a; 1. 所有数据存储在叶子节点 与B树不同&#xff0…

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(十三)图优化SLAM的本质

一、直白解释slam与图优化的结合 我从b站上学习理解的这个概念。 视频的大概位置是1个小时以后&#xff0c;在第75min到80min之间。图优化SLAM是怎么一回事。 slam本身是有运动方程的&#xff0c;也就是运动状态递推方程&#xff0c;也就是预测过程。通过t1时刻&#xff0c…

PyCharm2024.2.4安装

一、官网下载 1.从下面的链接点进去 PyCharm: The Python IDE for data science and web development by JetBrains 2.进入官网后&#xff0c;下载pycharm安装包 3.点击下载能适配你系统的安装包 4.安装包下载完成 二、安装 1.下载完成后&#xff0c;打开点击右键&#xff…