单调队列
一、性质
单调队列和单调栈很像,就是一个维护了单调性的队列数据结构,可以是单调递增的也可以是单调递减的
单调队列和普通队列的关系
1.单调队列的队首和普通的队列一样,只能删除元素
2.单调队列的队尾即可以添加元素也可以删除元素
单调队列也可以叫做输入受限的双端队列
二、单调队列的功能及作用
功能:在每次加入或者删除元素时都保持序列里的元素有序,即队首元素始终是最小值或者最大值;
作用:简单来说就是用来维护一段区间内的单调上升/下降性质,导出性质就是也可以用来维护一个区间内的最值;
为了能更好的理解单调队列,下面来举个例子
我们依次像队列中加入五个元素,5,8,2,4,1,假设队列单调递减,则队首元素始终最大,五次操作如下:
1:5
首先队列里面没有元素,把5加进去
2:8
第二个元素8大于队尾的元素所以要把5弹出,8加进去。保持队首最大
3:8 2
第三个元素2小于队尾元素,直接把2加到8后面
4:8 4
4大于队尾元素2,把2弹出,4小于8,直接将4加到8后面
5:8 4 1
1小于队尾元素4,直接把1加到4后面,队列最终为8 4 1
实现
单调队列我们用数组来进行模拟,下面是求每个长度为2的区间的最小值
首先设置队首和队尾指向的下标
注:队首指向0,队尾指向-1,默认队列里面没有元素
其次对队列
1.检查队首:如果队首指向的下标<=i-k即队首元素已经跑出了k长度即[i-k+1,i]这个区间,那么就要将队首元素弹出来,对应将h加一
2.检查队尾:如果队尾的元素>要添加的值,如果这个值加上去队列就不会保持单调性,所以要弹出队尾元素,对应t减一。目的就是保持队首元素一直是最小值且队列单调
3.加入队尾元素:q[++t]=i,首先t加一要腾出位置,加入的是元素的下标
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N],q[N];
int n,k;
int main()
{
cin>>n>>k;
int h=0,t=-1;//设置队首和队尾指向的下标
for(int i=1;i<=n;i++)
{
cin>>a[i];
//插入元素
while(h<=t&&i-k>=q[h])
{
h++;
}
while(h<=t&&a[q[t]]>=a[i])
{
t--;
}
q[++t]=i;
if(i>=k)//区间条件处的处理
{
cout<<a[q[h]]<<" ";
}
}
cout<<endl;
return 0;
}
输入
5 2
3 4 1 6 2
输出
3 1 1 2