滑动窗口算法
滑动窗口算法
今天复习了一下滑动窗口算法的框架,我第一次看的时候是有点懵逼的,现在回过头来再看一次的时候发现框架和思路都非常清晰,瞬间豁然开朗。下面会以四道力扣上的题来进行举例说明滑动窗口算法的奥秘。
- 76.最小覆盖字串(困难)
- 567.字符串的排列(中等)
- 438.找到字符串中所有字母异位词(中等)
- 3.无重复字符的最长子串(中等)
基本框架
滑动窗口算法其实是有一点双指针的技巧在里面的,技巧思路其实就是维护一个窗口,不断通过滑动这个窗口,然后同时更新答案。
基本框架如下:
1 | int left = 0, right = 0; //定义左右两边的指针 |
完整框架
只要理解了该框架,基本上可以秒杀大部分滑动窗口问题。其核心思路,也就是我们该如何向窗口中添加新元素,什么时候应该缩小窗口,在窗口滑动的哪个阶段应该更新结果。
框架如下:
1 | void slidingWindow(String s, Strint t){ |
滑动窗口算法思路
1.我们对于字符串S中使用双指针中的左右指针技巧,初始化左右指针为left=right=0,把索引左闭右开区间[left,right)称为一个窗口Window。
2.首先在满足不超过字符串S长度的情况下,我们不断的将right指针向右移动,left指针先不变,达到扩大窗口的效果。直到窗口中的字符串包含了T字符串中的所有字符串,right指针则停止移动。
3.此时,left指针开始向右移动,达到缩小窗口的效果,直到窗口中的字符串不再包含T中的所有字符串了,那么我们就要停止left指针的移动了。并且每次增加了left指针都要更新一次数据结果,比如说我们要更新窗口内符合要求的字符串有多少。
4.重复第2和第3步的操作,直到right指针到达字符串S的尽头。
下面根据图片来理解一下,其中集合need和window就是相当于两个计数器
不断将right指针向右移动,直到[left,right]中包含了T中的所有字符。
当满足所有要求后,left指针就开始向右移动,不断的缩小窗口达到最优化结果。
当窗口内的字符串都符合要求了,那么这个left指针就停止移动了。
之后就是重复上述的过程了,首先移动right再移动left,直到right指针到达字符串S的末端,程序结束。为什么要重复移动呢?因为你不能保证你第一次拿到的窗口就是最优的,因此要继续往下搜索。如果到达程序的末尾都没有比第一次得到的窗口更优了,那就可以直接返回结果了。
框架如何使用
首先就是要初始化两个哈希表,记录窗口中的字符和需要凑齐的字符。
然后就是使用left和right指针初始化窗口的两端。
1 | int left = 0, right = 0; |
其中valid是表示窗口中满足need条件的字符个数,如果valid和need.size的大小相同,则说明窗口已经满足条件,即已经包含了T字符串中的所有字符。
套模板之前,我们需要思考一些问题:
1.当移动right指针扩大窗口时,即加入字符到窗口Window里面时应该更新哪些数据呢?
2.在什么条件下,窗口应该停止扩大,开始移动left缩小窗口?
3.当移动left缩小窗口的时候,也就是移除字符时,应该更新哪些数据呢?
下面就用几道例题来说明一下