滑动窗口算法详解
**滑动窗口(Sliding Window)**是解决数组或字符串子区间问题的利器。无论是'最小覆盖子串',还是'长度最小的子数组',滑动窗口都能以 O(n) 的时间复杂度优雅解决。
1. 为什么要学滑动窗口?
LeetCode 209. 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target。找出该数组中满足其和 ≥ target 的长度最小的连续子数组,并返回其长度。
输入: target = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的子数组。
暴力解法思路
- 枚举所有可能的子数组
- 计算每个子数组的和
- 找出满足条件的最短子数组
// 暴力解法 O(n²)
int minSubArrayLen_brute(int target, vector<int>& nums) {
int n = nums.size();
int minLen = INT_MAX;
// 枚举所有起始位置
for (int i = 0; i < n; i++) {
int sum = 0;
// 枚举所有结束位置
for (int j = i; j < n; j++) {
sum += nums[j];
if (sum >= target) {
minLen = min(minLen, j - i + 1);
break; // 找到了就 break,因为后面的更长
}
}
}
return minLen == INT_MAX ? 0 : minLen;
}
暴力解法的问题分析
当 n=10000 时,需要约 1 亿次操作,严重超时。
滑动窗口的优化思路
观察:窗口的连续性
假设我们有一个窗口 [2,3,1] 和为 6 < 7。
- 传统做法: 丢弃整个窗口,从 3 重新开始。
- 聪明做法: 为什么不只丢弃左边的 2,保留 [3,1] 呢?
当前窗口:[2,3,1] 和=6 < 7 扔掉左边:移除 2 → [3,1] 和=4 加入右边:加入 2 → [3,1,2] 和=6 加入右边:加入 4 → [3,1,2,4] 和=10 ≥ 7 这样避免了重复计算 [3,1] 的和!

