滑动窗口核心思想
滑动窗口算法的核心在于用两个指针维护一个动态的区间。通过移动左右指针来扩大或缩小窗口,通常在一次遍历中就能完成计算,时间复杂度往往能优化到 O(n)。
典型应用场景:寻找最长无重复字符子串、找到和为目标值的最短子数组、字符串排列匹配等。
通用模板思路:
- 定义 left 和 right 指针,初始都指向起始位置;
- right 向右移动进窗口,更新状态;
- 当窗口不满足条件时,left 向右移动出窗口,直到重新满足;
- 在合法状态下更新结果。
结束条件通常是 right 指针越界。理解了这个框架,我们来看几个具体的例子。
案例一:长度最小的子数组
问题描述
给定一个含有 n 个正整数的数组和一个正整数 target,找出该数组中满足其和 ≥ target 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
解题思路
由于数组元素均为正整数,累加和具有单调性,这非常适合套用滑动窗口模板。
- 初始化 left 和 right 指针,同时指向首元素;
- right 指针向右移动,将元素加入窗口并累加 sum;
- 当 sum >= target 时,说明当前窗口满足条件,尝试收缩左边界以寻找更短的子数组:left 右移,sum 减去 nums[left],直到 sum < target;
- 每次收缩前都要记录当前窗口的最小长度。
注意:在收缩窗口(left 移动)的过程中,只要依然满足 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]; // 进窗口,累加
while(sum >= target) { // 保证窗口合法
len = min(len, right - left + 1); // 更新结果
sum -= nums[left++]; // 出窗口
}
right++; // 继续进窗口
}
len == INT_MAX ? : len;
}
};


