leecode/thinkings/slide-window.md
2020-05-22 18:17:19 +08:00

100 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 滑动窗口Sliding Window
笔者最早接触滑动窗口是`滑动窗口协议`滑动窗口协议Sliding Window Protocol属于 TCP 协议的一种应用,用于网络数据传输时的流量控制,以避免拥塞的发生。 发送方和接收方分别有一个窗口大小 w1 和 w2。窗口大小可能会根据网络流量的变化而有所不同但是在更简单的实现中它们是固定的。窗口大小必须大于零才能进行任何操作。
我们算法中的滑动窗口也是类似,只不过包括的情况更加广泛。实际上上面的滑动窗口在某一个时刻就是固定窗口大小的滑动窗口,随着网络流量等因素改变窗口大小也会随着改变。接下来我们讲下算法中的滑动窗口。
## 介绍
滑动窗口是一种解决问题的思路和方法,通常用来解决一些连续问题。 比如 LeetCode 的 [209. 长度最小的子数组](https://leetcode-cn.com/problems/minimum-size-subarray-sum/solution/209-chang-du-zui-xiao-de-zi-shu-zu-hua-dong-chua-2/)。更多滑动窗口题目见下方`题目列表`。
## 常见套路
滑动窗口主要用来处理连续问题。比如题目求解“连续子串 xxxx”“连续子数组 xxxx”就应该可以想到滑动窗口。能不能解决另说但是这种敏感性还是要有的。
从类型上说主要有:
- 固定窗口大小
- 窗口大小不固定,求解最大的满足条件的窗口
- 窗口大小不固定,求解最小的满足条件的窗口(上面的 209 题就属于这种)
后面两种我们统称为`可变窗口`。当然不管是哪种类型基本的思路都是一样的,不一样的仅仅是代码细节。
### 固定窗口大小
对于固定窗口,我们只需要固定初始化左右指针 l 和 r分别表示的窗口的左右顶点并且保证
1. l 初始化为 0
2. 初始化 r使得 r - l + 1 等于窗口大小
3. 同时移动 l 和 r
4. 判断窗口内的连续元素是否满足题目限定的条件
- 4.1 如果满足,再判断是否需要更新最优解,如果需要则更新最优解
- 4.2 如果不满足,则继续。
![](https://tva1.sinaimg.cn/large/00831rSTly1gcw0pwdhmwj308z0d53yt.jpg)
### 可变窗口大小
对于可变窗口,我们同样固定初始化左右指针 l 和 r分别表示的窗口的左右顶点。后面有所不同我们需要保证
1. l 和 r 都初始化为 0
2. r 指针移动一步
3. 判断窗口内的连续元素是否满足题目限定的条件
- 3.1 如果满足,再判断是否需要更新最优解,如果需要则更新最优解。并尝试通过移动 l 指针缩小窗口大小。循环执行 3.1
- 3.2 如果不满足,则继续。
形象地来看的话,就是 r 指针不停向右移动l 指针仅仅在窗口满足条件之后才会移动,起到窗口收缩的效果。
![](https://tva1.sinaimg.cn/large/00831rSTly1gcw0ouuplaj30d90d50t3.jpg)
## 模板代码
### 伪代码
```
初始化慢指针 = 0
初始化 ans
for 快指针 in 可迭代集合
更新窗口内信息
while 窗口内不符合题意
扩展或者收缩窗口
慢指针移动
返回 ans
```
### 代码
以下是 209 题目的代码,使用 Python 编写,大家意会即可。
```python
class Solution:
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
l = total = 0
ans = len(nums) + 1
for r in range(len(nums)):
total += nums[r]
while total >= s:
ans = min(ans, r - l + 1)
total -= nums[l]
l += 1
return 0 if ans == len(nums) + 1 else ans
```
## 题目列表
以下题目有的信息比较直接,有的题目信息比较隐蔽,需要自己发掘
- [【PythonJavaScript】滑动窗口3. 无重复字符的最长子串)](https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/pythonjavascript-hua-dong-chuang-kou-3-wu-zhong-fu/)
- [76. 最小覆盖子串](https://leetcode-cn.com/problems/minimum-window-substring/solution/python-hua-dong-chuang-kou-76-zui-xiao-fu-gai-zi-c/)
- [209. 长度最小的子数组](https://leetcode-cn.com/problems/minimum-size-subarray-sum/solution/209-chang-du-zui-xiao-de-zi-shu-zu-hua-dong-chua-2/)
- [【Python】滑动窗口438. 找到字符串中所有字母异位词)](https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/solution/python-hua-dong-chuang-kou-438-zhao-dao-zi-fu-chua/)
- [【904. 水果成篮】Python3](https://leetcode-cn.com/problems/fruit-into-baskets/solution/904-shui-guo-cheng-lan-python3-by-fe-lucifer/)
- [【930. 和相同的二元子数组】JavaPython](https://leetcode-cn.com/problems/binary-subarrays-with-sum/solution/930-he-xiang-tong-de-er-yuan-zi-shu-zu-javapython-/)
- [【992. K 个不同整数的子数组】滑动窗口Python](https://leetcode-cn.com/problems/subarrays-with-k-different-integers/solution/992-k-ge-bu-tong-zheng-shu-de-zi-shu-zu-hua-dong-c/)
- [【1004. 最大连续 1 的个数 III】滑动窗口Python3](https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/1004-zui-da-lian-xu-1de-ge-shu-iii-hua-dong-chuang/)
- [【1234. 替换子串得到平衡字符串】[Java/C++/Python] Sliding Window](https://leetcode.com/problems/replace-the-substring-for-balanced-string/discuss/408978/javacpython-sliding-window/367697)
- [【1248. 统计「优美子数组」】滑动窗口Python](https://leetcode-cn.com/problems/count-number-of-nice-subarrays/solution/1248-tong-ji-you-mei-zi-shu-zu-hua-dong-chuang-kou/)
## 扩展阅读
- [LeetCode Sliding Window Series Discussion](https://leetcode.com/problems/binary-subarrays-with-sum/discuss/186683/)