滑动窗口 单调队列
本人水平有限,题解不到为处,请多多谅解
本蒟蒻谢谢大家观看
题目:传送门
很明显求最值问题,还带区间,用单调队列来维护保证时间复杂度在O(N),每个元素出队进队各一次,所以在O(1)内即可完成。
1:维护队首(就是如果你已经是当前的m个之前那你就可以被删了,head++)
2:在队尾插入(每插入一个就要从队尾开始往前去除冗杂状态)
我们要维护两个单调队列,一个递增,一个递减。
递增单调队列:
其中num表示枚举到的位置,num[head]表示头结点所在的位置,因为此时i表示当前枚举的位置,k表示需要的个数,所以num[head]<i-k+1为头结点所在的位置,当且仅当head<=tail时,头结点才会扩展,表示队内有元素。
a[i]表示当前位置上的值,q[tail]表示单调队列中末尾的值,如果a[i]<q[tail]表示当前的值小于队列末端的值,因为我们首先维护的是单调递增队列,
只要队列里有元素,并且尾元素比待处理值大,即表示尾元素已经不可能继续在队内,所以出队。直到尾元素小于待处理值(队首肯定最小,依次递增),满足"单调"递增。将尾部元素不断插入至队列中,直到第一个入队的尾部元素成了头结点时,保证q[head]为最小值
递减单调队列:
同理可得:a[i]>q[tail]表示当前值大于队内末端元素值,因为我们维护的是单调递减队列
只要队列里有元素,并且尾元素比待处理值小,即表示尾元素已经不可能继续在队内,所以出队。直到尾元素大于待处理值(队首肯定最大,依次递减),满足"单调"递减。将尾部元素不断插入至队列中,直到第一个入队的尾部元素成了头结点时,保证q[head]为最大值
code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,k,Fmax[1000010],num[1000010],q[1000010],Fmin[1000010]; 4 int a[1000010]; 5 int head,tail; 6 void dmin() 7 { 8 head=1; 9 tail=0; 10 for(int i=1;i<=n;i++) 11 { 12 while(num[head]<i-k+1&&head<=tail)head++; 13 while(a[i]<q[tail]&&head<=tail)tail--; 14 num[++tail]=i; 15 q[tail]=a[i]; 16 Fmin[i]=q[head]; 17 } 18 } 19 void dmax() 20 { 21 head=1; 22 tail=0; 23 for(int i=1;i<=n;i++) 24 { 25 while(num[head]<i-k+1&&head<=tail)head++; 26 while(a[i]>q[tail]&&head<=tail)tail--; 27 num[++tail]=i; 28 q[tail]=a[i]; 29 Fmax[i]=q[head]; 30 // cout<<"i-k+1= "<<i-k+1<<endl; 31 // cout<<"i= "<<i<<endl; 32 // cout<<"num[head]= "<<num[head]<<endl; 33 // cout<<"head= "<<head<<endl; 34 // cout<<"tail= "<<tail<<endl; 35 // cout<<"num[++tail]= "<<num[++tail]<<endl; 36 // cout<<"q[tail]= "<<q[tail]<<endl; 37 // cout<<"q[head]= "<<q[head]<<endl; 38 } 39 } 40 int main() 41 { 42 cin>>n>>k; 43 for(int i=1;i<=n;i++) 44 cin>>a[i]; 45 dmin(); 46 dmax(); 47 for(int i=k;i<n;i++) 48 cout<<Fmin[i]<<" "; 49 cout<<Fmin[n]<<endl; 50 for(int i=k;i<n;i++) 51 cout<<Fmax[i]<<" "; 52 cout<<Fmax[n]<<endl; 53 return 0; 54 }