单调队列的作用,归纳成一句话就是不断读入元素,不时去掉元素,随时查询最值
应用的话就比较高级了,除了滑动窗口这个题目,还有动态规划的效率优化,当然还有别的以后再整理
单调队列由于要不断从两端进行队列操作,所以采用双端队列来实现
在此例中,所有的数据都是放在a数组中的,我们用一个p来表示a数组中某一个元素的下标,然后在单调队列中存下标即可
我们以维护单调递增队列举例
while(!q.empty()&&a[p]<=a[q.back()]) //维护单调队列 q.pop_back(); q.push_back(p);
对于一个新的p,我们用a[p]和当前单调队列的最后一个位置的元素作比较,如果发现比新插入元素的大的,全部扔出去,因为我这个队列只维护单调增,只方便找最小值即可,大的没用
然而,对于一些过期的元素,虽然他们很小,我们还是要把它们扔掉才可以
while(!q.empty()&&q.front()<p-k+1) //维持题意的区间长度 q.pop_front(); //移出出界的元素
接下来根据题意输出队列中元素的值即可
由于我们是单调递增队列,维护的是最小值,那么队首元素就是最有用的
if(p>=k-1) //元素进够k个后开始输出答案 cout<<a[q.front()]<<" "; p++;
下面给出滑动窗口的完整实现
1 //aininot260 2 //不断读入元素,不时去掉元素,随时询问最值 3 #include<iostream> 4 #include<queue> 5 using namespace std; 6 const int maxn=1000005; 7 int n,k; 8 int a[maxn]; 9 deque<int> q; 10 int main() 11 { 12 cin>>n>>k; 13 for(int i=0;i<n;i++) 14 cin>>a[i]; 15 int p=0; 16 while(p<n) 17 { 18 while(!q.empty()&&a[p]<=a[q.back()]) //维护单调队列 19 q.pop_back(); 20 q.push_back(p); 21 while(!q.empty()&&q.front()<p-k+1) //维持题意的区间长度 22 q.pop_front(); //移出出界的元素 23 if(p>=k-1) //元素进够k个后开始输出答案 24 cout<<a[q.front()]<<" "; 25 p++; 26 } 27 cout<<endl; 28 29 p=0; 30 q.clear(); 31 while(p<n) 32 { 33 while(!q.empty()&&a[p]>=a[q.back()]) //维护单调队列 34 q.pop_back(); 35 q.push_back(p); 36 while(!q.empty()&&q.front()<p-k+1) //维持题意的区间长度 37 q.pop_front(); //移出出界的元素 38 if(p>=k-1) //元素进够k个后开始输出答案 39 cout<<a[q.front()]<<" "; 40 p++; 41 } 42 cout<<endl; 43 return 0; 44 }
原文:https://www.cnblogs.com/aininot260/p/9304573.html