滑动窗口算法详解
滑动窗口是一种常用的双指针技巧,通过维护一个动态的区间(窗口),利用左右指针的移动来扩大或缩小范围。相比暴力枚举,它通常能将时间复杂度优化至 O(n)。
典型应用场景
- 寻找最长无重复字符的子串
- 找到和为目标值的最短子数组
- 字符串排列匹配
- 包含特定数量元素的子序列
核心思路与模板
滑动窗口的本质是模拟一个'窗口'在数据流上滑动。一般步骤如下:
- 初始化:定义
left和right指针,同时指向起始位置。 - 扩展窗口:移动
right指针进入窗口,更新当前状态(如求和、计数)。 - 收缩窗口:当窗口不满足条件时,移动
left指针移出元素,直到重新满足条件。 - 记录结果:在每次合法状态下更新最优解。
- 结束条件:当
right遍历完整个数组或字符串。
下面我们通过四个经典题目来深入理解这一思想。
1. 长度最小的子数组
题目描述
给定一个含有 n 个正整数的数组和一个正整数 target,找出该数组中满足其和 ≥ target 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
实现思路
由于数组元素均为正整数,累加和具有单调性,非常适合使用滑动窗口。
- 进窗口:
right向右移动,累加sum。 - 判断:当
sum >= target时,说明当前窗口满足条件,尝试更新最小长度。 - 出窗口:为了寻找更短的满足条件的子数组,移动
left指针,减去nums[left],直到sum < target。
注意:在收缩窗口的过程中,只要
sum >= target,都要尝试更新一次结果,因为此时可能已经找到了更优解。
代码实现
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left = 0, right = 0;
int len = INT_MAX, sum = 0;
while (right < nums.size()) {
sum += nums[right];
(sum >= target) {
len = (len, right - left + );
sum -= nums[left++];
}
right++;
}
len == INT_MAX ? : len;
}
};


