滑动窗口多应用于求满足某条件的子数组!
题目源自知乎 https://zhuanlan.zhihu.com/p/61564531
eg:给定一个含有 n 个正整数的数组和一个正整数s,找出该数组中满足其和≥s的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
输入: n = 6, s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组,[2,3,1,2]满足和 ≥ 7,但不是最短的。
朴素算法(两轮遍历 注意i是左端点 j是右端点):
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 10;
int a[N];
int main(){
int n,s;
cin >> n >> s;
int min_;
vector<int> count;
for(int i = 0; i < n; i++) cin >> a[i];
for(int i = 0; i < n; i++){ //双指针的遍历
for(int j = i; j < n; j++){
int k = i,sum = 0;
while(k <= j) sum+=a[k++];
cout << sum << ' ';
if(sum >= s) {
count.push_back(k - i);
break;
}
}
}
sort(count.begin(),count.end());
cout << count[0];
}
朴素算法中,有很多重复的计算,比如若[2,3]和≤7,那么[3]和一定≤7;同理若[2,3,1]和≤7,那么[3,1]和一定≤7;而[2,3,1,2]和≥7,此时[3,1,2]和不一定≤7!就需要继续进一步分析。因此,排除必不可能出现的情况,只对有可能的情况展开讨论,就可以大大降低时间复杂度。
那么就可以让上述朴素算法中的i(左端点)也滑动起来,每当j遍历结束找到第一个满足和≥7的子序列后,i向右滑动直至使得子序列不再满足和≥7的条件,过程中可能会有满足和≥7的子序列,此时也需要更新长度。
举个栗子!
[3,1,2,4]满足条件,此时i向右滑动,[1,2,4]仍满足条件,此时需要更新长度为3!继续右滑动,[2,4]不再满足条件,于是j继续右滑。
滑动窗口可以由队列实现!
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 1000010;
int a[N], e[N], tt, hh;
void init(){
tt = -1;
hh = 0;
}
void push(int x){
e[++tt] = x;
}
string empty(){
if(tt < hh) return "YES";
else return "NO";
}
void pop(){
hh ++;
}
int query(){
return e[hh];
}
int main(){
int i,n,k;
cin >> n >> k;
for(int i = 0; i < n; i++) cin >> a[i];
int sum;
vector<int> count;
init();
while(i < n){ //直至所有元素被加入队列中 o(n)
while(sum <= k){
push(i++); //入队
sum += a[e[tt]]; //求和
}
count.push_back(e[tt]-e[hh]+1); //统计队列中元素个数
while(sum >= k){
sum -= a[e[hh]]; //减掉最左侧的数
pop(); //出队
if(sum >= k) count.push_back(e[tt]-e[hh]+1); //统计队列中元素个数
}
}
sort(count.begin(),count.end());
cout << count[0];
}