当前位置:   article > 正文

数据结构 - 单调队列入门_数据单调性

数据单调性

今天我们来聊聊单调队列
单调单调,就代表这种队列具有单调性
而单调性又分为单调递增与单调递减
举个栗子:

1 4 5 6 7 8 10
  • 1

这就是一个单调递增的序列

1 4 6 5 7 8 10
  • 1

就不是
而这和我们的“单调队列”又有什么关系呢?
单调队列的作用就是将区间最小或者最大值维护在队首
那么我们要怎么维护呢?
给同学们思考1年
大家解放自己的脑洞,试想一下如果一个队列从队首到队尾单调递减,那么队首不就是区间最大值了吗?
没错!这就是“单调队列”的一个核心思想
于是乎,构建单调队列的方法也非常明显了
比如

1 7 5 4 8 2 6
  • 1

我们怎样创建一个区间最大值单调队列呢?
我们需要保证队列单调递减
工程开始:
i=1,a[i]=1,队首为0,0<1,清空队列,1入队,队列为 ( 1 )
i=2,a[i]=7,队首为1,1<7,清空队列,7入队,队列为 ( 7 )
i=3,a[i]=5,队首为7,7>5,队尾为7,7>5,5入队,队列为 ( 7 , 5 )
i=4,a[i]=4,队首为7,7>4,队尾为5,5>4,4入队,队列为 ( 7 , 5 , 4 )
i=5,a[i]=8,队首为7,7<8,清空队列,8入队,队列为 ( 8 )
i=6,a[i]=2,队首为8,8>2,队尾为8,8>2,2入队,队列为 ( 8 , 2 )
i=7,a[i]=6,队首为8,8>6,队尾为2,2<6,2出队,6入队,队列为 ( 8 , 6 )
工程结束。
大家可以发现,在每一个过程中,我们都对队首队尾进行了判断,保证了队列的单调递减,成功维护了队首为区间最大值

例题 P1886 滑动窗口

原题链接
0、首先读题,发现这题要维护区间的最大值与最小值,判断算法为单调队列
1、创建 4 个队列maxn,minx,x,y,分别用于存储区间最大最小值及序号,推荐使用 STL 的 deque
2、从数组的第一个元素开始遍历,先对前 m-1 个元素创建单调队列,再继续创建单调队列
3、如果当前元素比 maxn 队首元素要大,说明队中的所有元素都比当前元素小,清空队列,当前元素入队
从队尾开始将比当前元素小的元素全部弹出
如果队首的序号超出本区间,弹出队首
minx 队列的做法与 maxn 相似,大家可以试着举一反三
代码仅供参考:

#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000005],ans1[1000005],ans2[1000005];
deque <int> maxn,minx,x,y;//注意用deque
inline int read()
{
    int x=0,w=1;
    char ch=0;
    while(ch<'0' || ch>'9')
    {
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9') x=(x << 3)+(x << 1)+ch-'0',ch=getchar();
    return x*w;
}
//读优 
int main()
{
    n=read();
    m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<m;i++)
    {
        while(!maxn.empty() && a[i]<=maxn.back()) maxn.pop_back(),x.pop_back();
        while(!minx.empty() && a[i]>=minx.back()) minx.pop_back(),y.pop_back();
        maxn.push_back(a[i]);
        x.push_back(i);
        minx.push_back(a[i]);
        y.push_back(i);
    }//重要,先对前 m-1 个元素创建单调队列
    for(int i=m;i<=n;i++)
    {
        while(!maxn.empty() && a[i]<=maxn.back()) maxn.pop_back(),x.pop_back();
        while(!minx.empty() && a[i]>=minx.back()) minx.pop_back(),y.pop_back();
        maxn.push_back(a[i]);
        x.push_back(i);
        minx.push_back(a[i]);
        y.push_back(i);
        while(!maxn.empty() && i-x.front()>=m) maxn.pop_front(),x.pop_front();
        while(!minx.empty() && i-y.front()>=m) minx.pop_front(),y.pop_front();//单调队列的维护
        ans1[i]=maxn.front();
        ans2[i]=minx.front();//记录答案
    }
    for(int i=m;i<=n;i++) printf("%d ",ans1[i]);
    printf("\n");
    for(int i=m;i<=n;i++) printf("%d ",ans2[i]);//输出即可
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

原创 By Venus
写的不好大佬轻喷

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/429856
推荐阅读
相关标签
  

闽ICP备14008679号