滑动窗口的核心思想
在数组或字符串上维护区间 [left, right],通过 右扩探索、左缩修正 的方式,在线性时间内统计或优化子串/子数组性质。
适用信号词:连续子数组/子串、至多/至少 k 个、最长/最短、和 ≥ target。与 week01-two-pointers 同向指针相似,但窗口强调 区间状态 的增量更新。
固定窗口
窗口长度恒为 k。例如「长度为 k 的子数组最大和」:先算前 k 个和,再滑动——加入 nums[right]、移除 nums[right-k]。
def max_sum_subarray(nums, k):
window = sum(nums[:k])
best = window
for right in range(k, len(nums)):
window += nums[right] - nums[right - k]
best = max(best, window)
return best
找所有长度为 k 的子串:右移时同步更新哈希计数,比较是否匹配模式串。
可变窗口
最长无重复子串
用 last[ch] 记录字符上次出现下标;若重复且位置 ≥ left,则 left = last[ch] + 1。
def length_of_longest_substring(s):
last = {}
left = ans = 0
for right, ch in enumerate(s):
if ch in last and last[ch] >= left:
left = last[ch] + 1
last[ch] = right
ans = max(ans, right - left + 1)
return ans
和 ≥ target 的最短子数组
右扩累加 total,当 total >= target 时不断左缩并更新最小长度。
def min_subarray_len(target, nums):
left = total = 0
ans = float("inf")
for right, x in enumerate(nums):
total += x
while total >= target:
ans = min(ans, right - left + 1)
total -= nums[left]
left += 1
return 0 if ans == float("inf") else ans
至多 K 个不同字符的最长子串
右扩增加种类数;当种类 > K 时左缩直到 ≤ K,更新最长长度。
窗口状态设计
| 题目类型 | 维护量 | 左缩条件 | |----------|--------|----------| | 无重复 | 字符最后位置 | 出现重复 | | 异位词 | 26 计数差 | 窗口满且匹配 | | 和/积约束 | total / product | 违反不等式 |
乘积 < k 类题:右扩乘积,超限时左除;注意零的处理(归零后重新开窗)。
常见陷阱
与哈希结合
「连续子数组和为 k」用前缀和 + 哈希计数;滑动窗口则用于 正整数和 ≥ target 等单调场景。分清何时用前缀和(允许负数)、何时用窗口(正数单调)。
配合 week01-hash-table 与站内算法章节,建议刷:无重复子串、最小覆盖子串、水果成篮(至多两种类型)三类模板题各一道。
实战巩固与面试表达
本篇属于 8 周冲刺 week01-sliding-window 主题。复习时先闭卷回答 frontmatter 中三张 flashcard,再展开口述两个「为什么」:为什么这种方案能 work、边界失败时如何降级。与相邻章节对照:算法篇强调复杂度与模板,Go 篇强调工程默认写法,中间件篇强调线上故障案例。
动手与自检清单
用 25 分钟限时做 1 道相关练习题或画出一张架构/数据结构示意图;用 5 分钟写 STAR 片段说明你在项目里是否用过类似技术。记录 3 个面试追问及你的标准答法,存入 /zh/notebook/master-plan 笔记。若某点不熟,回到对应 /chapters 交互 Lab 重新走一遍流程,比死记卡片更有效。
易错点提醒
避免只背名词不会画图;避免只说优点不谈 trade-off(性能、一致性、运维成本至少提一项);避免把学习 Demo 说成百万 QPS 生产。回答时使用「场景 → 方案 → 结果 → 反思」四段式,体现工程成熟度。