滑动窗口
滑动窗口主要思考以下几个问题
(1)当移动right应当更新什么数据
(2)什么条件下要停止扩大开始收缩left
(3)left缩小应该更新什么数据
(4)我们要的结果是在扩大时候更新还是缩小的时候更新
/* 滑动窗口算法框架 */
void slidingWindow(string s, string t) {
unordered_map<char,int> need,window;
for (char c:t) need[c]++;
int left=0, right=0;
int valid=0;
while (right< s.size()) { //特别要注意的是,这里维持的是一个左闭右开的区间[left,right).因为终止边界上 //right==s.size()
//c是将移入窗口的字符
char c=s[right];
// 右移窗口
right++;
// 进行窗口内数据的一系列更新
...
/*** debug 输出的位置 ***/
printf("window: [%d, %d)\n", left, right);
/********************/
// 判断左侧窗口是否要收缩
while(window needs shrink) {
// d 是将移出窗口的字符
char d=s[left];
// 左移窗口
left++;
// 进行窗口内数据的一系列更新
...
}
}
}
调试很重要
更加重要的是你要知道窗口维持的是一个左闭右开的这么一个区间(很重要的一个细节)
示例
leetcode 209题
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的连续子数组,返回 0。
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的连续子数组。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
//可以用滑动窗口和动态规划做
//第一种解法:滑动窗口
int n=nums.size();
if(nums.empty()) return 0; //排除为空
int len=0,left=0,right=0,sum=0;
int res=INT_MAX;
while(right<n) //注意这里维持的是一个左闭右开的搜索窗口
{
int a=nums[right];
right++;
sum+=a;
//窗口数据更新
if(sum<s)
{
len=right-left;
}
//什么时候要收缩左边界
while(sum>=s) //代表找到了,这时候该缩小左边界,并且更新sum,和res
{
len=right-left;
int b=nums[left];
left++;
sum-=b;
res=min(res,len);
}
}
return (res==INT_MAX)?0:res; //这里判断是不是没有找到
}
};