【优选算法 — 滑动窗口】水果成篮 找到字符串中所有字母异位词

news2024/11/16 2:40:54

   

 


  水果成篮  


水果成篮


 

  题目描述  

因为只有两个篮子,每个篮子装的水果种类相同,如果从 0 开始摘,则只能摘 0 和 1 两个种类 ;

  • 因为当我们在两个果篮都装有水果的情况下,如果再走到下一颗果树,果树的水果种类不是果篮中的任意一种,则停止采摘;
  • 所以就是要找出一块连续的区域,这个连续的区域最多有两种类型的元素,并且在所有找到的符合条件的区域中,找出长度最长的区域;

通过上述例子,我们可以把题目描述最终简化成一个问题模型:

找出长度最长的子数组,子数组中的元素种类<=2


  解法:滑动窗口  

  • 定义 left 指针固定一个起点,然后定义 right 指针向后枚举;
  • 枚举出所有合适的子数组,然后返回所有子数组中长度最长的数组

  • 模拟一个 hash 表 kinds,来统计水果出现的个数;
  • 每 right 遍历一个元素,就把该元素对应的 kinds[ fruits [ i ] ] ++;
  • 然后每次改变 kinds的元素 kinds[ fruits [ i ] ] ,都要判断 kinds 这个数组的有效元素个数是否小于3 ;

如果想不清楚进窗口和出窗口该怎么操作,就回到暴力枚举的基础上,来模拟出进出窗口的操作:

  1. left = 0 ,right = 0;new kinds[ ];
  2. 进窗口(kinds[fruit [ right ] ]++,right++)
  3. 循环判断 3,4,5(kinds.length 是否 >2)
  4. 出窗口(kinds[fruit [ left ] ]--,left++);
  5. 如果因为 kinds[ fruit [ left ] ]--,导致 kinds[fruit [ left ] ] 变成0,则要移除这个元素
  6. 更新结果(不断更新 ret 直到最后拿到最大值)

Map 官方文档


    编写代码: 

 

    分析错误原因: 

  • 因为出窗口这行代码的逻辑,是更新 kinds 中的计数;
  • 如果放到 if 的下面,那么在检查计数为空之前,如果 output 对应的计数原本就是1,那么 if 条件在更新之前就会检查一个过时的值(即1,而不是更新后的0);
  • 意味着,可能 remove 操作不能被正确的执行,所以会报错;
  • 因此,出窗口的操作必须在 if 的前面去更新;

  正确写法  

  方法一:使用容器 Map  

  方法二:用数组模拟哈希表  

根据题目给的上述提示,为了降低执行用时,我们可以通过一个数组模拟哈希表


   找到字符串中所有字母异位词   


找到字符串中所有字母异位词


 

  1.先快速判断两个字符数相同的字符串是否是“异位词”  

对于这两个字符数相同的字符串,我们如何判断这两个字符串是一个异位词呢?


我们可以先分别对 这两个字符串 的 所有字符 进行排序,然后使用 双指针 依次比对这两个字符串对应的字符即可;

这个方法虽然可以达到目的,但是因为排序操作,使得时间复杂度太高了;

所以,如果是两个字符数相同的字符串,要比较是不是异位词,我们可以统计每一个字符出现的个数即可,因为异位词是不考虑顺序的。

所以我们可以通过哈希表,快速判断两个词是否是异位词:

   暴力解法   

   总结规律   

所以这个枚举的过程,都是从左到右枚举的,所以可以用滑动窗口的解法来解决:

   解法:滑动窗口 + 哈希表   


  • 之前做的关于滑动窗口的题目,窗口大小是不固定的,这题是第二种滑动窗口的题型,就是窗口大小固定(left 和 right 同时移动);
  • 只要定义的两个指针从始至终都是同向移动的,就是滑动窗口的题型;

  1. left = 0 , right = 0;
  2. 定义 hash1 统计 p 字符串中字符的 key,val
  3. 进窗口(定义 hash2,right++,hash2.get(s[ right ])++)
  4. 判断(right - left + 1 > m)(因为窗口大小固定,left 只需要移动一次,所以判断不用写成循环))
  5. 出窗口(hash2.get(s[ right ])--,left++,)
  6. 更新结果 ( check(hash1,hash2) ,返回 true,子串的首元素下标放入返回的 list 中)
  7. 循环 3 4 5 6

   优化 check()    


因为 s 和 p 都是小写字母,所以我们只需要创建一个大小为 26 的数组模拟哈希表即可,数组下标模拟的是哈希表的 key。

那么每次程序执行到调用 check() 的地方,check()中,仅仅需要比较 26 次每个元素的值是否相同即可。


   时间复杂度    

因此,在上述优化后,时间复杂度 O(26*N) —> O(N)


因为我们这道题,哈希表存的是一个一个的字符,所以我们可以用字符数组来模拟哈希表,这时候,比较两个字符数组是非常快的;

但是,如果遇到哈希表存的 key,是一个一个的字符串,就不能再用数组模拟哈希表了


   优化 check() 的判断条件   


我们如果直接调用 check(),来直接比较两个哈希表是否相同 ,是需要比较 26 次才可以出结果的;

如果换难一点的题,可能需要比较更多次,才可以知道两个两个哈希表是否相同,因此我们需要优化 check() 的判断条件;

做法:利用 count 来统计窗口中“有效字符”的个数,一定要注意有效字符的定义

我们要在进窗口的操作过程中,维护 count;

此时,hash1 和 hash2 的 都有一个 c;

  • 所以,在往 hash2 添加了一个字符后,这个字符在 hash1 中也有;
  • 并且这个字符在放入 hash2 后,修改后的个数数字,是小于等于hash1对应字符的个数数字的

满足以上两点,就可以称为是“有效字符”,而 count 就是用来统计这些字符的个数的。

right++,如果遍历到的字符放入 hash2 后,对应的 val 大于 hash1,则说明是无效字符,count不更新

此时,我们需要判断一下,count 是否等于3(p.length),如果 count 刚好等于3(p.length),说明此时,窗口中的字符全是有效字符

所以一边通过进窗口操作更新哈希表,一边可以维护 count;当然,上面说的只是入窗口,出窗口也需要维护 count


思考:此时滑动窗口,right 指向新的字符 a,需要更新 count 吗?

是需要的;但是此时的窗口太大了,需要让 left++,并且从 hash2 中移出出窗口的元素

并且在 left 向后移动的这一步的过程中,第一个 c 变成了多余元素,而第二个 c 变成有效元素;

所以在这一步 left 后挪的过程中,是不改变 count 的值的;

此时的窗口大小等于 p.length,继续向后移动 right,遍历到的字符 e 加到 hash2 中;

每次 right++ 后,需要再次判断窗口的长度,会发现窗口长度大于 p.length,所以又需要调整 left;

在调整 left 之前,我们需要判断此时的  left  是否是一个有效元素

left 指向的元素在 hash2 的 val ,如果小于等于 hash1 中的对应元素的val,则 left 是有效元素;

对于上图的情况,left 向后移动删除的元素是一个有效元素,因此 count--

最后,只需要判断 count 是否与 p.length 相等即可,这样就不需要遍历 26 次了


   总结优化 check() 的判断方法的步骤   

  1. 进窗口:进窗口后,判断 hash2[ input ] <= hash1[ input ]  —> count++
  2. 出窗口:出窗口前,判断  hash2[ input ] <= hash1[ input ] —> count--
  3. 更新结果:只需要判断 count 是否等于 p.length,是则把当前 left 更新到 list 中

   优化后: 

   正确代码: 

   注意:序号一   原因:序号二   


   

 

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

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

相关文章

【ubuntu16.04】机器人学习笔记遇到的问题及解决办法:仿真小海龟

18版本的后面会出问题&#xff0c;避免万一我还是用了之前的16版本&#xff0c;虽然还没有解决粘贴的问题&#xff0c;但是安装ros很成功 可参考该文章博主讲的很详细&#xff0c;成功画出海龟 最后要把鼠标停在第三个终端&#xff0c;再去点击键盘&#xff0c;海龟才会动哦

游戏引擎学习第九天

视频参考:https://www.bilibili.com/video/BV1ouUPYAErK/ 修改之前的方波数据&#xff0c;改播放正弦波 下面主要讲关于浮点数 1. char&#xff08;字符类型&#xff09; 大小&#xff1a;1 字节&#xff08;8 位&#xff09;表示方式&#xff1a;char 存储的是一个字符的 A…

探索 JNI - Rust 与 Java 互调实战

真正的救赎&#xff0c;并非厮杀后的胜利&#xff0c;而是能在苦难之中&#xff0c;找到生的力量和内心的安宁。 ——加缪Albert Camus 一、Rust Java &#xff1f; Java 和 Rust 是两种现代编程语言&#xff0c;各自具有独特的优势&#xff0c;适用于不同的应用场景。 1、…

C++11新特性(二)

目录 一、C11的{} 1.初始化列表 2.initializer_list 二、可变参数模版 1.语法与原理 2.包扩展 3.empalce接口 三、新的类功能 四、lambda 1.语法 2.捕捉列表 3.原理 五、句装器 1.function 2.bind 一、C11的{} 1.初始化列表 C11以后想统⼀初始化⽅式&#xff0…

生信:TCGA学习(R、RStudio安装与下载、常用语法与常用快捷键)

前置环境 macOS系统&#xff0c;已安装homebrew且会相关命令。 近期在整理草稿区&#xff0c;所以放出该贴。 R语言、RStudio、R包安装 R语言安装 brew install rRStudio安装 官网地址&#xff1a;https://posit.co/download/rstudio-desktop/ R包下载 注意R语言环境自带…

Vue3集成搜索引擎智能提示API

需求&#xff1a; 如何在项目中实现像百度搜索框一样的智能提示效果&#xff0c;如下图所示&#xff1a; 相关知识&#xff1a; 下面是各厂商提供的免费API 厂商请求百度http://suggestion.baidu.com/su?wd中国&cbwindow.baidu.sug必应http://api.bing.com/qsonhs.as…

大数据技术在智慧医疗中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 大数据技术在智慧医疗中的应用 大数据技术在智慧医疗中的应用 大数据技术在智慧医疗中的应用 引言 大数据技术概述 定义与原理 发…

游戏引擎学习第10天

视频参考:https://www.bilibili.com/video/BV1LyU3YpEam/ 介绍intel architecture reference manual 地址:https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html RDTS&#xff08;读取时间戳计数器&#xff09;指令是 x86/x86_64 架构中的…

「QT」文件类 之 QTemporaryDir 临时目录类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「Win」Windows程序设计「IDE」集成开发环境「UG/NX」BlockUI集合「C/C」C/C程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「UG/NX」NX定制…

Kettle配置数据源错误“Driver class ‘org.gjt.mm.mysql.Driver‘ could not be found”解决记录

问题描述 错误提示&#xff1a;“Driver class ‘org.gjt.mm.mysql.Driver’ could not be found, make sure the ‘MySQL’ driver (jar file) is installed.” 原因分析&#xff1a; 根据错误提示是缺少了相关的数据源连接jar包。 解决方案&#xff1a; 安装对应的Mysql…

C++《继承》

在之前学习学习C类和对象时我们就初步了解到了C当中有三大特性&#xff0c;分别是封装、继承、多态&#xff0c;通过之前的学习我们已经了解了C的封装特性&#xff0c;那么接下来我们将继续学习另外的两大特性&#xff0c;在此将分为两个章节来分别讲解继承和多态。本篇就先来学…

力扣(LeetCode)283. 移动零(Java)

White graces&#xff1a;个人主页 &#x1f649;专栏推荐:Java入门知识&#x1f649; &#x1f439;今日诗词:雾失楼台&#xff0c;月迷津渡&#x1f439; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主&#x1f64f; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主…

运算放大器的学习(一)输入阻抗

输入阻抗 最近需要对运算放大器进行学习&#xff0c;我们后面逐一对其参数进行了解。 首先了解下输入阻抗。 放大电路技术指标测试示意图&#xff1a; 输入电阻&#xff1a; 从放大电路的输入端看进去的等效电阻称为放大电路的输入电阻&#xff0c;如上图&#xff0c;此处考虑…

Python3.11.9下载和安装

一、Python3.11.9下载和安装 1、下载 下载地址&#xff1a;https://www.python.org/downloads/windows/ 选择版本下载&#xff0c;例如&#xff1a;Python 3.11.9 - April 2, 2024 2、安装 双击exe安装 3、配置环境变量 pathD:\Program Files\python3.11.9 pathD:\Progr…

大模型研究报告 | 2024年中国金融大模型产业发展洞察报告|附34页PDF文件下载

随着生成算法、预训练模型、多模态数据分析等AI技术的聚集融合&#xff0c;AIGC技术的实践效用迎来了行业级大爆发。通用大模型技术的成熟推动了新一轮行业生产力变革&#xff0c;在投入提升与政策扶植的双重作用下&#xff0c;以大模型技术为底座、结合专业化金融能力的金融大…

杰控通过 OPCproxy 获取数据发送到服务器

把数据从 杰控 取出来发到服务器 前提你在杰控中已经有变量了&#xff08;wincc 也适用&#xff09; 打开你的opcproxy 软件包 opcvarFile 添加变量 写文件就写到 了 opcproxy.ini中 这个文件里就是会读取到的数据 然后 opcproxy.exe发送到桌面快捷方式再考回来 &#…

Vue3 -- 环境变量的配置【项目集成3】

环境&#xff1a; 在项目开发过程中&#xff0c;至少会经历开发环境、测试环境和生产环境(即正式环境)三个阶段。 开发环境 .env.development测试环境 .env.test生产环境 .env.production 不同阶段请求的状态(如接口地址等)不一样&#xff0c;开发项目的时候要经常配置代理跨…

vxe-table 分享实现无限滚动行方式

Vxe UI vue vxe-table 分享无限滚动行方式 实现无限滚动加载有多种方式&#xff0c;可以使用 scroll 事件&#xff0c;也可以使用 scroll-boundary 事件&#xff0c;能满足不同的需求场景。 以下是分享使用 scroll-boundary 事件的用法。 原理 通过 scrollY.threshold 设置阈…

C++中的栈(Stack)和堆(Heap)

在C中&#xff0c;堆&#xff08;heap&#xff09;和栈&#xff08;stack&#xff09;是两种用于存储数据的内存区域。理解它们的原理和区别&#xff0c;对于优化代码性能和确保代码的安全性至关重要。以下是对C中堆栈的详细解析&#xff0c;包括它们的分配方式、优缺点、应用场…

outlook邮箱关闭垃圾邮件——PowerAutomate自动化任务

微软邮箱反垃圾已经很强大了非常敏感&#xff0c;自家的域名的邮件都能给扔到垃圾邮箱里&#xff0c;但还是在本地增加了一层垃圾邮箱功能&#xff0c;然后垃圾邮箱并没有提示&#xff0c;导致错过很多通知&#xff0c;本身并没有提供关闭的功能&#xff0c;但微软有个Microsof…