滑动窗口算法¶
概述¶
滑动窗口(Sliding Window)是一种重要的算法思想,通过维护一个动态窗口在序列上滑动,将嵌套循环问题转化为单循环问题,将时间复杂度从O(n²)降低到O(n)。
滑动窗口的核心价值
滑动窗口算法是处理数组/字符串子区间问题的利器。它通过维护窗口内的状态,避免了重复计算,实现了线性时间复杂度。熟练掌握滑动窗口是算法竞赛和面试的必备技能。
算法思想详解¶
什么是滑动窗口¶
graph TB
A["固定窗口大小 k"] --> B["窗口从左向右滑动"]
B --> C["每次滑动一步"]
C --> D["维护窗口内状态"]
D --> E["高效计算窗口结果"]
style E fill:#E8F5E9
窗口类型¶
| Text Only | |
|---|---|
可视化演示¶
经典问题实现¶
1. 固定窗口最大和¶
2. 滑动窗口最大值(单调队列)¶
graph LR
subgraph "单调队列维护"
A["新元素加入队尾"] --> B["弹出所有小于新元素的队尾元素"]
B --> C["新元素入队"]
C --> D["弹出队首过期元素"]
end
style D fill:#E8F5E9
3. 最长无重复字符子串¶
4. 最小覆盖子串¶
C++ 实现¶
滑动窗口框架¶
graph TB
subgraph "滑动窗口通用框架"
A["初始化: left=0, 窗口状态"] --> B["right遍历数组"]
B --> C["更新窗口状态 加入right元素"]
C --> D{"窗口满足条件?"}
D -->|是| E["记录结果"]
D -->|否| F["继续扩展"]
E --> G["尝试收缩窗口 while循环"]
G --> H["更新窗口状态 移除left元素"]
H --> I["left++"]
I --> D
F --> B
end
style E fill:#E8F5E9
复杂度分析¶
| 问题 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|
| 固定窗口最大和 | O(n) | O(1) | 每个元素进出窗口各一次 |
| 滑动窗口最大值 | O(n) | O(k) | 单调队列最多k个元素 |
| 最长无重复子串 | O(n) | O(字符集) | 哈希表存储字符位置 |
| 最小覆盖子串 | O(n) | O(字符集) | 哈希表存储字符计数 |
滑动窗口 vs 暴力¶
graph TB
A["子区间问题"] --> B{"是否可以用滑动窗口?"}
B -->|是| C["O n 时间复杂度"]
B -->|否| D["暴力枚举 O n² "]
C --> E["关键特征:<br/>1. 区间连续<br/>2. 可增量维护状态<br/>3. 有单调性或可优化条件"]
style C fill:#E8F5E9
应用场景¶
1. 数组/字符串子区间问题¶
- 最大/最小子数组和
- 子数组平均值
- 最长/最短满足条件的子数组
2. 字符串匹配问题¶
- 最小覆盖子串
- 找到所有anagram
- 最长无重复子串
3. 数据流问题¶
- 滑动窗口中位数
- 滑动窗口第K大元素
- 移动平均值
4. 图像处理¶
- 滑动窗口滤波
- 局部特征提取
常见变体¶
1. 定长滑动窗口¶
2. 可变长滑动窗口(双指针)¶
3. 乘积小于K的子数组个数¶
参考资料¶
- 《算法导论》- 分治与滑动窗口
- Sliding Window Technique - LeetCode
- 滑动窗口算法总结
- LeetCode 3, 76, 209, 239, 438, 567