【算法】滑动窗口


滑动窗口

1.概念

滑动窗口是一类很常见的题型,最常见的就是子串问题,因为滑动窗口是一个连续的,所以很容易就是问满足条件的最大或者最小子串啊,这个条件就是不同的地方,但万变不离其宗,滑动窗口就是一个窗口的移动。

总之:子串+最值 --> 滑动窗口

滑动窗口有两大类

  • 固定长度的滑动窗口:窗口的大小是固定好的,这是其实分为了窗口形成和人窗口滑动两个过程,窗口形成就是要先让窗口达到要求的长度; 窗口滑动的过程在右边界长的时候,左边界也要跟着长,维持窗口长度不变;
  • 可变长度的滑动窗口:这也是遇到最多的,控制窗口移动的原因不是长度,而是是否达到题目中某一条件,如果达到此条件,那右边界停下,左边界开始移动,试图去破坏这一条件,就是在这个过程中不断的更新结果。

2.过程

  • 1.从题目中先整理出条件,常见的比如说子序列的和大于某值,子串中包含某些值,子串中出现了重复值,先把这些条件找出来,这就是用来移动窗口的依据;
  • 2.初始化left和right指针都为0,right指针从头走到尾,当不满足上面的条件时,right走,一直走到这个窗口满足上面我们总结出来的条件了,停下;
  • 3.记录下我们要的答案,比如最典型的问子串的最小长度啊啥的,记录下这时候我们的right-left+1,这就是目前窗口的大小;
  • 4.右边走不动了那左边就得开始走了,移动左指针,每次移动都要把左指针的值给去除,因为我们统计的结果只能是窗口里的结果,出去了自然就不要了,然后,每一次左指针的移动都要判断是否满足条件,比如要求子串和大于某一值,左边移动一步,减去这个值看还大于目标值吗,如果满足,更新我们最终要的最小子串,因为这时候子串长度肯定缩小了嘛,直到不满足条件为止;如果不满足,那左指针不用再动了,右指针可以开始动了,寻找下一个满足条件时停下来。
  • 5.就这样重复,右边动完左边动,左边动完右边再动;

总结:右边界要使窗口达到某一条件,左边界使窗口跳出这一条件

3.模板

int left = 0, right = 0;
while(right < nums.length){
    result = result + nums[right]; 
    //更新窗口内数据;
    //将移入窗口的值添加进结果,这里就是不同题目不同要求;比如和,比如哈希表等;   
    while(判断是否达到条件){  //如果达到条件左窗口就要收缩了;
        res = Math.min(res, right-left+1); //只要满足条件每次都要更新答案;
        //更新窗口内数据;
        result = result - nums[left]; //左窗口的值从结果去除;
        left++; //左窗口移动;
    }
    right++;  //只要不满足条件右窗口移动;
}

其实,我们的右边界就是在努力满足条件,找到一个可行解,而我们的左边界呢,想让这个可行解更好一点,比如长度更短一下,是在寻找一个更好的最优解,但是很可能玩脱了不满足条件。

在套模板的时候我们需要思考以下问题:

  • 1.当移动right,即加入结果的时候,需要更新哪些数据;
  • 2.到达什么条件时,窗口停止扩大,也就是右边界停下来,开始左边界移动,缩小窗口;
  • 3.当移动left,即移出结果的时候,需要更新哪些数据;
  • 4.要的最后答案应该在窗口扩大还是窗口缩小时更新;

4.样例

3. 无重复字符的最长子串

209. 长度最小的子数组

剑指 Offer 59 - I. 滑动窗口的最大值

424. 替换后的最长重复字符

5.体会

  • 要能够根据题目要求找到条件,因为条件是指挥我们移动左窗口还是右窗口的长官,不满足条件,右窗口移动; 满足条件,左窗口移动;
  • 要始终清楚左右两个边界都是不会回退的,都是朝着最后走的,不可能会出现往回走的时候;
  • 两个窗口不会同时移动,每次只有两个窗口中的一个移动。
  • 换种思路:我们的窗口滑动其实就是一个双端队列。当不满足条件时,数组元素依次从队尾入队;当满足条件时,队首元素出队;所以有的时候去想象成一个队列,可能会更好的理解;


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM