数据结构:单调队列

单调队列的作用,归纳成一句话就是不断读入元素,不时去掉元素,随时查询最值

应用的话就比较高级了,除了滑动窗口这个题目,还有动态规划的效率优化,当然还有别的以后再整理

单调队列由于要不断从两端进行队列操作,所以采用双端队列来实现

在此例中,所有的数据都是放在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