单调队列/单调栈入门详解+题目推荐

Posted hanruyun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单调队列/单调栈入门详解+题目推荐相关的知识,希望对你有一定的参考价值。

以前一直以为这两个是很高级的东西,这段时间用到了才开始学,发现实际上非常简单

下面我们以单调队列为例进行讲解,单调栈自行类比


顾名思义

单调队列这个名字就指明了它的性质——单调性

我们来看一道例题——滑动窗口

题面在此不再赘述,大意就是有一个长度为(n)的数列,一个长度为(k)的窗口,输出窗口位于每个位置下的下的最大最小值

嗯,题目很好理解,st表或者线段树过的先别说话,我们来看看另一种方法

我们维护一个长度为k的队列,使得队列的开头为答案,那么我们每次只需要输出开头就好了。这个想法很好,可是怎么实现呢?

最大值为例,既然我们想要保证队列开头为答案,那么我们就要保证每次更新使最大值一直放在队列。那么如果存储的最大值该弹出了怎么办呢?我们只需要记录下每个元素的位置,判断是否在区间内即可。

队头弹出后,第二位就变成了队头,我们就要保证这个数现在是区间内最大。那么是不是说,我们需要将这个长度为(k)的区间中的每一个数都存起来呢?不是的,并不是每个数被记录都有意义的。举个例子,(a_i)(a_j)两个数,i<j。如果(a_i)>(a_j),那么两个数都应该记录;但是如果(a_i≤a_j),那么当(a_j)进入区间后,(a_i)的记录就没有意义了。很好理解,我们假设每个数作为区间最大值的次数为它的贡献,当(a_j)进入区间以后,在区间中存在的时间一定比(a_i)长,也就说明(a_i)一定不会再做贡献了,我们确定没有贡献的点,便可以直接删去,以维护单调队列的单调性。

那么这道题也就已经做出来了,我们再来看看代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#define ll long long
#define gc() getchar()
#define maxn 1000005
using namespace std;

inline ll read(){
    ll a=0;int f=0;char p=gc();
    while(!isdigit(p)){f|=p=='-';p=gc();}
    while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
    return f?-a:a;
}

struct ahaha{    //v表示数的大小,pos表示数的位置
    int v,pos;
}q[maxn];
int n,a[maxn],h=1,t,k;
int main(){
    n=read();k=read();
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1;i<=n;++i){
        while(h<=t&&q[h].pos+k<=i)++h;    //维护区间长度,使队列内的数都在区间内
        while(h<=t&&q[t].v>=a[i])--t;    //维护队列单调性,上已证明
        q[++t].v=a[i];q[t].pos=i;      //将当前元素放入队尾
        if(i>=k)printf("%d ",q[h].v);
    }
    h=1;t=0;
    printf("
");
    for(int i=1;i<=n;++i){
        while(h<=t&&q[h].pos+k<=i)++h;
        while(h<=t&&q[t].v<=a[i])--t;
        q[++t].v=a[i];q[t].pos=i;
        if(i>=k)printf("%d ",q[h].v);
    }
    return 0;
}

看到这里,你应该已经对单调队列有了一个初步的理解,下面推荐几道入门题(顺序与难度无关)

单调队列

扫描

逛画展

琪露诺

切蛋糕

单调栈

[USACO09MAR]向右看齐Look Up

Bad Hair Day

Feel Good

Largest Rectangle in a Histogram

以上是关于单调队列/单调栈入门详解+题目推荐的主要内容,如果未能解决你的问题,请参考以下文章

单调栈

单调栈算法 入门+博客推荐+模板

单调栈&单调队列入门

单调栈&单调队列入门

⭐算法入门⭐《队列 - 单调队列》中等03 —— LeetCode 918. 环形子数组的最大和

⭐算法入门⭐《队列 - 单调队列》中等04 —— LeetCode 剑指 Offer 59 - II. 队列的最大值