滑动窗口专题

滑动窗口的核心在于用双指针维护一个满足特定条件的区间,并在移动过程中更新答案

五步进阶路线,从基础模板到结合高级数据结构的综合应用。


滑动窗口系统学习规划

第零步:前置 Python 技能确认

在开始之前,请确认你能熟练使用以下 Python 特性,它们是写出 Pythonic 滑动窗口的关键:

  • collections.Counterdefaultdict(int):用于窗口内元素的频率统计,替代手动 dict.get(x, 0)
  • 海象运算符 :=:在 while 循环条件中同时赋值和判断,常用于窗口收缩。
  • enumerate:在遍历右指针时同时获取索引和值。
  • max / min 与生成器表达式:用于在窗口内快速求最值(简单场景)。
  • all / any:用于检查窗口内元素是否满足某种条件。

第一步:定长窗口与基础模板 📏

核心思想 :窗口长度固定为 k,右指针逐格移动,左指针跟随。我们关注的是窗口滑入和滑出的元素,以及如何 O(1) 更新窗口状态,而不是每次都重新计算整个窗口。

预期收获

  1. 掌握定长滑动窗口的入窗-出窗标准模板。
  2. 理解"增量式更新"而非"全量重算"的效率差异。
  3. 学会用 Python 的切片与 Counter 简化窗口操作。

学完后自查

  • 能否用 for i, x in enumerate(arr) 控制右指针,用 i - k 定位左指针元素?
  • 能否用海象运算符 :=while 中收缩窗口(虽然定长不常用收缩,但要会写)?
  • 能否解释为什么定长窗口通常不需要 while 收缩循环?

📋 推荐练习(按顺序做)

# 题目 难度 Python 特异性技巧
1 643. Maximum Average Subarray I Easy 定长窗口模板入门,sum 滑动更新,注意浮点除法
2 1343. Number of Sub-arrays of Size K and Average Greater than or Equal to Threshold Easy 与上一题同模板,条件判断即可
3 1456. Maximum Number of Vowels in a Substring of Given Length Medium set 存元音,窗口更新时判断滑入/滑出元素
4 567. Permutation in String Medium 定长视角 :窗口大小固定为 s1 长度,用 Counter 比较两个频率字典是否相等

第二步:不定长窗口 --- 最长/最短子数组 🌊

核心思想 :窗口长度不固定,右指针扩展,当窗口不满足条件 时,while 循环收缩左指针直到重新满足。根据求最长 还是最短 ,答案在窗口满足条件时更新 还是收缩后更新

预期收获

  1. 掌握 while 收缩与 if 收缩的语义区别。
  2. 学会在扩展/收缩过程中正确维护窗口状态(频率、计数、和等)。
  3. 理解"有效窗口"与"无效窗口"的临界点管理。

学完后自查

  • 能否清楚地描述:求最长时,何时更新答案?求最短时,何时更新答案?
  • 能否用 defaultdict(int)Counter 维护频率,并在频率归零时删除键(del-=0 后处理)?
  • 能否正确使用 while 配合 := 写出紧凑的收缩逻辑?

📋 推荐练习(按顺序做)

# 题目 难度 Python 特异性技巧
5 209. Minimum Size Subarray Sum Medium 不定长窗口入门,求最短,while 收缩模板
6 3. Longest Substring Without Repeating Characters Medium setdefaultdict 维护无重复,收缩到满足为止,求最长
7 904. Fruit Into Baskets Medium 等价于"最多包含 2 种元素的最长子数组",用 Counter 维护种类数
8 76. Minimum Window Substring Hard 经典难题 :用两个 Counter(需求 vs 窗口实际),维护 haveneed 匹配计数

第三步:计数型窗口 --- 恰好 K 个与模式抽象 🔢

核心思想 :很多"恰好 K 个"的问题无法直接滑窗(因为窗口扩展时可能从 K 变成 K+1,收缩时又可能从 K 变成 K-1,难以单调维护)。核心技巧是转换为 "最多 K 个"减去"最多 K-1 个",从而复用不定长窗口模板。

预期收获

  1. 掌握"恰好" → "最多之差"的转换技巧。
  2. 学会将"元素种类数 ≤ K"作为窗口合法条件。
  3. 理解为什么直接求"恰好"往往需要前缀和+哈希,而"最多"可以直接滑窗。

学完后自查

  • 能否在 3 分钟内写出 atMost(K) 的模板函数?
  • 能否解释为什么 exact(K) = atMost(K) - atMost(K-1)
  • 能否识别什么样的"恰好"题不适合这个转换(提示:窗口条件非单调时)?

📋 推荐练习(按顺序做)

# 题目 难度 Python 特异性技巧
9 992. Subarrays with K Different Integers Hard "恰好 K 种" = atMost(K) - atMost(K-1)Counter 维护种类
10 1358. Number of Substrings Containing All Three Characters Medium "至少包含"可以反过来,但更适合用"最少"视角:找到最小窗口后,左指针右侧都可扩展
11 930. Binary Subarrays With Sum Medium 和恰好为 goal = atMost(goal) - atMost(goal-1),与上一题同模板
12 1248. Count Number of Nice Subarrays Medium 与上题几乎一样,只是把和变成奇数的计数

第四步:多元素状态与收缩条件多样化 🧮

核心思想 :不是所有窗口条件都是"频率"或"种类"。有时是 max - minsum 的上下界、或者需要维护窗口内的极值。这一阶段训练你根据题意设计状态变量的能力,而不再套固定模板。

预期收获

  1. 学会维护窗口内多个状态(如最大值、最小值、正/负数计数等)。
  2. 理解什么时候需要用 heapq 或单调队列来维护窗口极值(但完整实现留到第五步)。
  3. 能够灵活写出非频率类的收缩条件。

学完后自查

  • 能否在一个窗口内同时维护 sumcount_negative、以及某种"前缀信息"?
  • 能否正确写出 while 条件中组合多个逻辑的收缩规则?
  • 是否理解"收缩到何时停止"对答案正确性的影响?

📋 推荐练习(按顺序做)

# 题目 难度 Python 特异性技巧
13 1004. Max Consecutive Ones III Medium 维护窗口内 0 的个数,收缩到 ≤ K,求最长
14 2024. Maximize the Confusion of an Exam Medium 与上题同模式,两种字符各自算一遍
15 1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit Medium 需要维护窗口内 maxmin 的差值,用 heapq 惰性删除或单调队列
16 2401. Longest Nice Subarray Medium 窗口内元素两两位与为 0,等价于窗口 OR 和某个新元素与为 0,用位运算维护状态

第五步:滑动窗口 + 高级数据结构 ⚡

核心思想 :当窗口收缩条件依赖于窗口内的极值顺序信息 ,而直接扫描会退化为 O(nk) 时,需要引入单调队列(collections.deque 实现)或堆(heapq + 惰性删除)来在 O(1)O(log n) 内获取窗口最值。

预期收获

  1. 掌握 deque 实现单调队列的标准写法(维护单调递减队列取最大值)。
  2. 掌握 heapq + 窗口索引做"惰性删除"的技巧。
  3. 能够分析何时必须引入这些结构,何时简单的变量即可满足。
  4. 结合前缀和,解决"和 + 最值"类的滑动窗口问题。

学完后自查

  • 能否手写 deque 的单调递增/递减队列模板(while deque and nums[deque[-1]] < nums[right]: pop)?
  • 能否用 heapq 配合 while heap[0][1] < left: heappop 实现惰性删除?
  • 能否区分"窗口内任意元素"条件和"窗口内最值"条件在实现上的差异?

📋 推荐练习(按顺序做)

# 题目 难度 Python 特异性技巧
17 239. Sliding Window Maximum Hard 定长窗口 + 单调队列(deque),经典中的经典
18 862. Shortest Subarray with Sum at Least K Hard 前缀和 + 单调队列,窗口收缩条件涉及和与索引
19 480. Sliding Window Median Hard 定长窗口 + 对顶堆(两个 heapq)+ 惰性删除,中位数维护
20 1425. Constrained Subsequence Sum Hard DP + 单调队列优化,滑动窗口内取 dp 最大值

🎯 最终目标:完成这 20 题后,你应该能:

  • 看到滑动窗口题,脑海中自动浮现"定长/不定长/最多转恰好/需要单调队列"的分类。
  • 用 Python 的 Counterdefaultdictdequeheapq 写出简洁的窗口状态维护。
  • 在 15 分钟内解决 Medium 级别的滑动窗口题,30 分钟内解决 Hard 级别。
相关推荐
Omics Pro1 小时前
柳叶刀|参考文献不存在
人工智能·算法·机器学习·支持向量机·自然语言处理
初心未改HD1 小时前
机器学习之K-Means聚类算法详解
算法·机器学习·kmeans
yugi9878381 小时前
主动噪声控制中的 FXLMS 算法研究与 MATLAB 实现
开发语言·算法·matlab
Liangwei Lin1 小时前
LeetCode 394. 字符串解码
数据结构·算法
YuanDaima20481 小时前
动态规划基础原理与题目说明
数据结构·人工智能·python·算法·动态规划·手撕代码
大志出奇迹1 小时前
传输协议为大端,STM32为小端,数据传输的字节序问题
c语言·stm32·单片机·mcu·算法·rtos
我爱cope1 小时前
【滑动窗口:力扣438找到字符串中所有字母异位词】
算法·leetcode·职场和发展
happyprince1 小时前
06-FlagEmbedding 核心算法详解
算法
洛水水1 小时前
【力扣100题】27. 二叉树的最大深度
算法·leetcode·图论