滑动窗口专题

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

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


滑动窗口系统学习规划

第零步:前置 Python 技能确认

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

  • collections.Counter 与 defaultdict(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 用 set 或 defaultdict 维护无重复,收缩到满足为止,求最长
7 904. Fruit Into Baskets Medium 等价于"最多包含 2 种元素的最长子数组",用 Counter 维护种类数
8 76. Minimum Window Substring Hard 经典难题 :用两个 Counter(需求 vs 窗口实际),维护 have 和 need 匹配计数

第三步:计数型窗口 --- 恰好 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 - min、sum 的上下界、或者需要维护窗口内的极值。这一阶段训练你根据题意设计状态变量的能力,而不再套固定模板。

预期收获:

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

学完后自查:

  • 能否在一个窗口内同时维护 sum、count_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 需要维护窗口内 max 和 min 的差值,用 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 的 Counter、defaultdict、deque、heapq 写出简洁的窗口状态维护。
  • 在 15 分钟内解决 Medium 级别的滑动窗口题,30 分钟内解决 Hard 级别。
相关推荐
朝朝辞暮i2 小时前
C++ 第 31C 课:Subscriber 到底是什么
开发语言·c++·算法
Evand J2 小时前
【MATLAB例程】三维RRT+APF路径规划与AOA-TDOA融合定位算法。附代码的下载链接
算法·matlab·路径规划·rrt·tdoa·apf·aoa
海绵宝宝转agent3 小时前
leetCode100算法开源笔记分享
笔记·算法
写后端的胖头鱼3 小时前
时间复杂度 & 空间复杂度
java·数据结构·算法·时间复杂度·空间复杂度
hahaha60163 小时前
黑体轨迹和色温--光源白点
人工智能·嵌入式硬件·算法·计算机视觉
海绵宝宝转agent3 小时前
基于Redis ZSet+AOP+注解实现限流注解算法
数据库·redis·算法
All for pursuit.4 小时前
【回溯-7】494.目标和
数据结构·c++·算法·leetcode
白杨尚青4 小时前
C++入门篇(十三):vector(上)——动态数组:构造、空间增长与迭代器失效
开发语言·c++·笔记·算法·stl
Jasmine_llq4 小时前
《P17461 [GESP202609 八级] 生成树计数》
算法·栈·tarjan 算法·边双连通分量·深度优先搜索 dfs·tarjan 保存当前路径节点·模乘法
Jasmine_llq4 小时前
《P17462 [GESP202609 八级] 末班车》
算法·dijkstra 算法·最大化版本,求最长可行值·建反向图(逆图 / 反转边)·多源 dijkstra 思想·对每个终点单独跑一遍djst·离线预处理 + 在线查询