前言

兄弟们,互联网寒冬期,算法刷着走。上篇文章讲了双指针的左右指针,双指针是数组类算法题中最重要的一个分支之一。这篇文章讲双指针技巧的滑动窗口。遇到双指针的题目,直接套用模板就完事儿。另外,数组有下图这些知识点与技巧。

思路

滑动窗口一般用于解决主串是否满足子串的某些需求问题,比如,是否包含某个字串,是否含有字串的所有字符等。
滑动窗口有固定的解题模板。但是细节众多,需要反复练习。

//s为原字符串,t为子字符串
public void slidingWindow(String s, String t) {//初始化窗口应该满足的条件needMap,key=子串t中的字符,value=字符在t字符串中出现的次数Map<Character, Integer> needMap = new HashMap<>();for (int i = 0; i < t.length(); i++) {Character k = t.charAt(i);needMap.put(k, needMap.getOrDefault(k, 0) + 1);}//滑动窗口中包含的字符,及其数量,key=滑动窗口中的字符,value=字符出现的次数Map<Character, Integer> winMap = new HashMap<>();//l:窗口左指针,r窗口右指针,validCount:窗口中有多少个字符满足了条件。int l = 0, r = 0, validCount = 0;while (r < s.length()) {//即将加入窗口的字符char in = s.charAt(r);//窗口右指针右移r++;//进行窗口内数据的操作...while (窗口是否应该收缩) {//即将从窗口移除的字符char out = s.charAt(l);//窗口左指针右移l++;//进行窗口内数据的操作...}}
}

最小覆盖子串

leetcode第76题

解题思路

套用滑动窗口模板。窗口左右指针下标从0开始遍历原字符串。

窗口的右指针右移后,判断加入窗口的字符是否是子串的字符,若是则更新winMap。更新后若winMap中该字符的value=needMap中该字符的value,说明滑动窗口中该字符数量与子串该字符的数量相等,则validCount+1。

当validCount=needMap.size()时,说明子串中的字符全部都包含在了滑动窗口中,且每个字符的字符数量也满足。这时就把窗口的左指针右移,直到窗口中的字符串不在符合要求为止。

重复上诉步骤,找出最小的窗口。

复杂度分析

时间复杂度:O(nlogz+mlogz),z是字符集的大小,n是原字符串的长度,m是子串长度。最坏情况下,窗口右指针会扫描一遍原数组,窗口左指针会扫描一边原数组,所以最多扫描2n次,而每扫描一次,就有若干次的map.get与map.put,则复杂度是nlogz。初始化needMap时,需要扫描一遍子串,且也有map.get与map.put。则复杂度为O(nlogz + mlogz)。

空间复杂度:O(z)。因为需要建立两个map分别存滑动窗口与字串中字符的出现次数,且每个map的键值对最多不会存放超过字符集的大小。

代码

class Solution {public String minWindow(String s, String t) {Map<Character, Integer> needMap = new HashMap<>();for (int i = 0; i < t.length(); i++) {Character k = t.charAt(i);needMap.put(k, needMap.getOrDefault(k, 0) + 1);}Map<Character, Integer> winMap = new HashMap<>();int l = 0, r = 0, validCount = 0, start = 0, minWin = Integer.MAX_VALUE;while (r < s.length()) {char in = s.charAt(r);r++;if (needMap.containsKey(in)) {winMap.put(in, winMap.getOrDefault(in, 0) + 1);//窗口中该字符的数量等于字串中该字符的数量if (winMap.get(in).equals(needMap.get(in))) {validCount++;}}//窗口中所有字符的数量都大于等于字串中字符的相应数量,说明这是一个满足题意的子串while (validCount == needMap.size()) {//记录满足条件时的最小窗口if (r - l < minWin) {start = l;minWin = r - l;}char out = s.charAt(l);l++;if (needMap.containsKey(out)) {winMap.put(out, winMap.getOrDefault(out, 0) - 1);//当窗口中该字符的数量小于了字串中的数量if (winMap.get(out) < needMap.get(out)) {validCount--;}}}}return Integer.MAX_VALUE == minWin ? "" : s.substring(start, start + minWin);}
}

字符串的排列

leetcode第567题

解题思路

套用滑动窗口模板。窗口左右指针下标从0开始去遍历s2。

窗口的右指针右移后,判断加入窗口的字符是否是s1的字符,若是则更新winMap。更新后若winMap中该字符的value=needMap中该字符的value,说明滑动窗口中该字符数量与s1中的该字符的数量相等,则validCount+1。

当validCount=needMap.size()时,说明s1中的字符全部都包含在了滑动窗口中。此时进行判断,当窗口的长度=s1的长度时,说明是一个合法序列,则返回true。

重复上诉步骤,若遍历结束后都没找到合法序列,则返回false。

复杂度分析

时间复杂度:O(nlogz + mlogz),z是字符集的大小。n 是s1字符串的长度,m是s2字串长度。最坏情况下,窗口右指针会扫描一遍s2,窗口左指针会扫描一遍s2,所以最多扫描2m次,而每扫描一次,就用若干次的map.get与map.put,则复杂度是mlogz。初始化needMap时,需要扫描一遍s1,每次扫描也有map.get与map.put。则复杂度为O(nlogz + mlogz)。

空间复杂度:O(z)。因为需要建立两个map分别存滑动窗口与字串中字符的出现次数,且每个map的键值对最多不会存放超过字符集的大小。

代码

class Solution {public boolean checkInclusion(String s1, String s2) {Map<Character, Integer> needMap = new HashMap<>();for (int i = 0; i < s1.length(); i++) {Character k = s1.charAt(i);needMap.put(k, needMap.getOrDefault(k, 0) + 1);}Map<Character, Integer> winMap = new HashMap<>();int l = 0, r = 0, validCount = 0;while (r < s2.length()) {char in = s2.charAt(r);r++;if (needMap.containsKey(in)) {winMap.put(in, winMap.getOrDefault(in, 0) + 1);if (winMap.get(in).equals(needMap.get(in))) {validCount++;}}while (validCount == needMap.size()) {if (r - l == s1.length()) {return true;}char out = s2.charAt(l);l++;if (needMap.containsKey(out)) {winMap.put(out, winMap.getOrDefault(out, 0) - 1);if (winMap.get(out) < needMap.get(out)) {validCount--;}}}}return false;}
}

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

leetcode第438题

解题思路

套用滑动窗口模板。窗口左右指针下标从0开始去遍历s。

窗口的右指针右移后,判断加入窗口的字符是否是p的字符,若是则更新winMap。更新后若winMap中该字符的value=needMap中该字符的value,说明滑动窗口中该字符数量与p中的该字符的数量相等,则validCount+1。

当validCount=needMap.size()时,说明p中的字符全部都包含在了滑动窗口中。此时进行判断,当窗口的长度=s的长度时,说明是一个合法序列,则加入列表中。

重复上诉步骤,找出所有的合法序列。

复杂度分析

时间复杂度:O(nlogz + mlogz),n是s字符串的长度,m是p字串长度。最坏情况下,窗口右指针会扫描一遍s,窗口左指针会扫描一遍s,所以最多扫描2n次,而每扫描一次,就用若干次的map.get与map.put,则复杂度是nlogz。初始化needMap时,需要扫描一遍p,每次扫描也有map.get与map.put。则复杂度为O(nlogz + mlogz)。

空间复杂度:O(z)。z是字符集的大小。因为需要建立两个map分别存滑动窗口与字串中字符的出现次数,且每个map的键值对最多不会存放超过字符集大小。

代码

class Solution {public List<Integer> findAnagrams(String s, String p) {Map<Character, Integer> needMap = new HashMap<>();for (int i = 0; i < p.length(); i++) {Character k = p.charAt(i);needMap.put(k, needMap.getOrDefault(k, 0) + 1);}Map<Character, Integer> winMap = new HashMap<>();List<Integer> list = new ArrayList<>();int l = 0, r = 0, validCount = 0;while (r < s.length()) {char in = s.charAt(r);r++;if (needMap.containsKey(in)) {winMap.put(in, winMap.getOrDefault(in, 0) + 1);if (winMap.get(in).equals(needMap.get(in))) {validCount++;}}while (validCount == needMap.size()) {if (r - l == p.length()) {list.add(l);}char out = s.charAt(l);l++;if (needMap.containsKey(out)) {winMap.put(out, winMap.get(out) - 1);if (winMap.get(out) < needMap.get(out)) {validCount--;}}}}return list;}
}

无重复字符的最长子串

leetcode第3题

解题思路

此题不能用常规的滑动窗口模板。由于没有子串,所以不需要needMap去统计子串的字符,也不需要validCount统计窗口内满足子串相关条件的字符数。

窗口左右指针下标从0开始去遍历s。窗口的右指针右移后,将加入窗口的字符更新进winMap。

当winMap中刚加入窗口的字符的value大于1,则说明窗口中有重复的字符了。开始右移左指针,并实时更新winMap,直到winMap中刚加入窗口的字符的value不大于1。此时窗口长度就是一个无重复的子串长度。

重复上诉步骤,找出最大子串长度。

复杂度分析

时间复杂度:O(nlogz),n 是s字符串的长度。最坏情况下,窗口右指针会扫描一遍s,窗口左指针会扫描一遍s,所以最多扫描2n次。而每扫描一次,就用若干次的map.get与map.put,则复杂度为O(nlogz)。

空间复杂度:O(z)。z是字符集的大小。因为需要建立一个map存滑动窗口中字符的出现次数,且map的键值对最多不会存放超过z是字符集的大小。

代码

class Solution {public int lengthOfLongestSubstring(String s) {Map<Character, Integer> winMap = new HashMap<>();int l = 0, r = 0, max = Integer.MIN_VALUE;while (r < s.length()) {char in = s.charAt(r);r++;winMap.put(in, winMap.getOrDefault(in, 0) + 1);while (winMap.get(in) > 1) {char out = s.charAt(l);l++;winMap.put(out, winMap.get(out) - 1);}max = Math.max(r - l, max);}return max == Integer.MIN_VALUE ? 0 : max;}
}

结尾

滑动窗口套路固定,遇到类型题时,直接模板默写代码,屡试不爽。 下篇文章讲二分搜索。

感谢各位人才的点赞、收藏和评论,干货文章持续更新中,下篇文章再见!

数组-滑动窗口(直接套模板完事儿)相关推荐

  1. 209. 长度最小的子数组(中等 数组 滑动窗口)

    209. 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target . 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, -, n ...

  2. leetcode刷题笔记-数组-滑动窗口

    一.滑动窗口的常见问题分析 问题 给定一个含有 n 个正整数的数组和一个正整数 target . 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, - ...

  3. POJ2823 滑动窗口 单调队列模板题 第一次用了发函数指针

    题意 有一个n长的序列,用k长的窗口在上面滑动,去每次窗口中最小和最大的数. 思路 使用单调队列,维护这个队列是单调的.以取最小元素为例,若窗口内左边元素>=右边元素,则左边元素失去保留的意义, ...

  4. 904. 水果成篮(滑动窗口)模板题

    在一排树中,第 i 棵树产生 tree[i] 型的水果. 你可以从你选择的任何树开始,然后重复执行以下步骤: 1,把这棵树上的水果放进你的篮子里.如果你做不到,就停下来. 2,移动到当前树右侧的下一棵 ...

  5. 常见面试算题题中的滑动窗口问题

    LeetCode1004. 最大连续1的个数 III 题目描述 给定一个由若干 0 和 1 组成的数组 A,最多可以将数组A中的 K 个元素的值从 0 变成 1 ,返回仅包含 1 的最长(连续)子数组 ...

  6. Python数据结构与算法篇(四)-- 滑动窗口算法

    数组和链表代表着计算机最基本的两种存储形式:顺序存储和链式存储,所以他俩可以算是最基本的数据结构.数组是一种基础数据结构,可以用来处理常见的排序和二分搜索问题,典型的处理技巧包括双指针.滑动窗口等,数 ...

  7. 【220】【3】滑动窗口(双指针)的应用,另有序的容器应用

    一.绝对值不超过限制的最长连续子数组的长度--滑动窗口 给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等 ...

  8. 列表左右箭头滑动_我写了一套框架,把滑动窗口算法变成了默写题

    读完本文,你可以去力扣拿下如下题目: 76.最小覆盖子串 567.字符串的排列 438.找到字符串中所有字母异位词 3.无重复字符的最长子串 ----------- 鉴于前文 二分搜索框架详解 的那首 ...

  9. 【CF 1195】Basketball Exercise/Submarine in the Rybinsk Sea (hard edition)/OpenStreetMap+二维单调队列滑动窗口模板

    寡人认为C,E都是比较板的题 butD2也太ex了,大大是被那个mod精给弄疯了,我mod了那么多次还是炸了longlong orz 文章目录 二维单调队列模板 C:Basketball Exerci ...

  10. LeetCode刷题:滑动窗口模板以及典型例题

    作者:fuxuemingzhu 链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/fen-xiang-hua- ...

最新文章

  1. 在PowerDesigner中设计概念模型
  2. jpa避免n+1_JPA技巧:避免N + 1选择问题
  3. 关于SimpleDateFormat线程不安全的源码分析
  4. qt 将int型数据显示在文本框_Qt编写Online judge爬虫
  5. Android下结束进程的方法
  6. “驱动能力”是什么意思???
  7. 机器学习实战(七)线性回归(Linear Regression)
  8. XDeepFM 模型,字节跳动短视频内容理解和推荐系统
  9. Windows Server 2008 R2远程用户数设置
  10. ie浏览器html播放器,ie浏览器播放不了网页视频
  11. Apache ShenYu源码阅读系列-Divide插件
  12. Java连接并操纵MySQL数据库的全过程
  13. Python实现分钟倒计时
  14. 「技术综述」人脸脸型分类研究现状
  15. 我是怎么提升写作能力的
  16. 一本修炼秘籍,带你打穿文件上传的21层妖塔(1)
  17. Jenkins+Allure测试报告+飞书机器人发送通知
  18. 什么是笔记本的南桥和北桥?
  19. 海康威视USB相机踩坑指南
  20. java正则匹配多个斜杠_正则表达式以匹配JAVA中的两个斜杠

热门文章

  1. Jsoup爬虫之Java爬虫工具类
  2. Vitamix和Blendtec破壁料理机哪个更高端?
  3. Gof 设计模式 完结
  4. 威纶通屏幕(HMI)开发基本教程一:如何获得学习资料来源
  5. AutoCAD-线型
  6. 史上最全最新手机号码号段大全
  7. 自定义填充图案插件 cad_CAD填充技巧:填充图案
  8. cad填充密度怎么调整_CAD填充图案时无法正常填充看似封闭的区域怎么解决?
  9. python 网格搜索_调参必备--Grid Search网格搜索
  10. WebStorm和VSCode配置