滑动窗口,答案一般在队首,队尾用于插入新的点。
1:窗口大小不变,依次滑动窗口,求窗口内最大值和最小值
有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值
int a[N],q[N],p[N];
int n,m;
//1 3 -1 -3 5 3 6 7
void mi(){
int h = 1,t = 0;//head -> tail 清空队列
for(int i=1;i<=n;i++){//枚举
while(h <= t && a[q[t]] >= a[i])//队列不空且新元素更优
t--;//队尾出队
q[++t] = i;//队尾入队
if(q[h] + m <= i)//队头出队
h++;
if(i >= m)
cout<<a[q[h]]<<" ";
}
}
void ma(){
int h = 1, t = 0;//head -> tail
for(int i=1;i<=n;i++){
while(h <= t && a[i] >= a[q[t]])
t--;
q[++t] = i;
if(q[h] + m <= i)
h++;
if(i >= m)
cout<<a[q[h]]<<" ";
}
}
2:连续子序列的最大和
int a[N],q[N],p[N],s[N];
int n,m,ans;
void mi(){
int h = 0 , t = 0;
q[0] = 0 , ans = s[1];
for(int i=1;i<=n;i++){
//判断队头元素是否要出队
if(h <= t && q[h] + m < i) h++;
//使用队头元素
ans = max(ans,s[i]-s[q[h]]);
//判断队尾元素是否需要出队(看是不是最优)
//找最小值时 队尾比该值大就出队
while(h <= t && s[q[t]] >= s[i])
t--;
//队尾插入新元素
q[++t] = i;
}
cout<<ans;
}
/*
s[i]-min(s[j],i-m <=j<= i-1)
即用单调队列找出窗口中的最小值
*/
int main(){
IOS;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
s[i] = s[i-1] + a[i];
}
ans = 0;
mi();
}
3:求每一个数左边第一个比他小的数
int a[N],q[N],n,m;
void mi(){//没有用到h
int h = 1 , t = 0;
for(int i=1;i<=n;i++){
//出队 直到找到比a[i]小的
while(t && a[i]<=a[q[t]]) t--;
if(t==0) cout<<"-1"<<" ";//没找到
else cout<<a[q[t]]<<" ";
q[++t] = i;//继续入队
}
}
/*
一个数如果被出队 他就不可能再是某个数的答案
10
4 7 6 8
8的答案是6 不会是已经出队的7
*/