滑动窗口算法核心解析
滑动窗口是一种常用的双指针技巧,通过维护一个动态的区间(窗口),利用左右两个指针的移动来扩大或缩小范围。这种方法通常能在一次遍历中完成计算,时间复杂度优化至 O(n)。
典型应用场景
- 寻找最长无重复字符的子串
- 找到和为目标值的最短子数组
- 字符串排列匹配
通用思路模板
虽然具体场景不同,但核心逻辑往往遵循以下步骤:
- 初始化:定义
left和right指针,初始指向首元素。 - 扩张窗口:当满足特定条件时,移动
right指针进入窗口,并更新当前状态(如求和、计数)。 - 收缩窗口:当不满足条件时,移动
left指针移出窗口,同时更新状态以维持窗口合法性。 - 记录结果:在每次窗口合法或状态变化时,根据需求更新最终答案。
- 结束条件:直到
right指针越界。
下面我们通过四道经典题目来深入理解这一思想。
1. 长度最小的子数组 (LeetCode 209)
题目描述
给定一个含有 n 个正整数的数组和一个正整数 target,找出该数组中满足其和 ≥ target 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
实现思路
由于数组元素均为正整数,累加和具有单调性。我们可以套用上述模板:
- 定义
left和right指针。 right向右移动,累加sum。当sum >= target时,说明当前窗口满足条件,尝试更新最小长度。- 此时开始收缩窗口:
left向右移动,从sum中减去nums[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]; // 进窗口,累加
(sum >= target) {
len = (len, right - left + );
sum -= nums[left++];
}
right++;
}
len == INT_MAX ? : len;
}
};


