滑动窗口题型:怎么识别、怎么讲、怎么练
滑动窗口不只是模板,而是一种把暴力枚举区间转成“扩张 + 收缩”过程的思考方式,所以它几乎统治了子串和子数组面试题。
覆盖题量
50+
推荐起手
写代码前先判断是定长窗口还是变长窗口。
高频误区
收缩条件写反,导致合法窗口被过早丢掉。
什么时候该想到这个模式
下手前的检查清单
真正适合面试表达的解题步骤
先确认答案确实可以由一个移动的连续区间推导出来。
选好窗口状态:和、不同元素个数、频次、匹配字符数等。
右指针扩张时立刻更新状态。
左指针只在窗口失效或超长时收缩。
用收缩后的有效窗口去更新答案。
常见变体
定长窗口
适合题目直接给定窗口长度,例如所有长度为 k 的子串。
变长窗口
适合条件由计数、和、覆盖关系决定,需要在失效时移动左边界。
窗口 + 频次数组
适合窗口合法性由重复字符或频次约束决定的情况。
模板预览
# Variable size sliding window
left = 0
window = {}
answer = 0
for right, value in enumerate(nums):
add(window, value)
while not is_valid(window):
remove(window, nums[left])
left += 1
answer = update(answer, left, right, window)
# Fixed size sliding window
window = initialize(nums[:k])
answer = evaluate(window)
for right in range(k, len(nums)):
remove(window, nums[right - k])
add(window, nums[right])
answer = update(answer, right - k + 1, right, window)
经典题目,不只是标题列表
更像真实刷题路径的推荐题单
这组题不是随机罗列,而是按“先建立识别感,再补关键变体,最后上强度”去排,适合真的拿来做一轮 pattern 复习。
入门建立直觉
#3 Longest Substring Without Repeating Characters
求不含重复字符的最长子串长度。
一旦字符重复,唯一能恢复合法性的动作就是右移左边界,别的操作都无法解决问题。
入门建立直觉
#209 Minimum Size Subarray Sum
求和至少为 target 的最短子数组长度。
正数保证了窗口和随指针移动具有单调性,这也是为什么这里滑窗比前缀和方案更自然。
变体补齐关键状态
#424 Longest Repeating Character Replacement
求最多替换 k 次后可变成同一字符的最长子串。
需要替换的字符数,等于窗口长度减去窗口内最高频字符的出现次数。
变体补齐关键状态
#567 Permutation in String
判断一个字符串是否包含另一个字符串的某个排列。
任何合法排列窗口长度都必须等于 s1,因此题目就变成:是否存在一个固定长度窗口,其字符频次刚好匹配。
高频难点压强练习
#76 Minimum Window Substring
找出包含 t 全部字符的最小子串。
核心状态不是简单的不同字符个数,而是“有多少种必需字符的需求频次已经被完全满足”。
高频坑点
收缩条件写反,导致合法窗口被过早丢掉。
窗口还没合法就更新答案。
左指针移动时忘了同步移除状态。
把定长窗口和变长窗口逻辑混在同一套循环里。
练习顺序建议
先刷定长窗口和频次数组题,例如排列匹配类。
再刷基础变长窗口,例如最短子数组和。
然后做覆盖型窗口,例如最小覆盖子串。
最后回头做需要计数器和多条件维护的高难混合题。