单调队列stl及手写实现,附例题

单调队列: 有单调性的队列(单调递增或递减),相比普通队列不同在于可以在队尾进行pop操作
特点: 可以快速取出最大值最小值(队首元素)
严格单调序列:a1<a2<a3<…<an,即a[i]和a[i+1]不能相等
时间复杂度: 每个元素出队入队各一次,总复杂度O(n),均摊下来每次维护队列的操作为O(1)
维护方法:
不严格单调递增为例:

  • 每次入队时与队尾元素比较,如果队列非空且小于(大于)队尾元素,就将队尾元素pop,重复上述操作直到队列为空或大于等于队尾元素,再将元素压入队尾。

STL实现方法:#include<deque>

deque是双端队列,既有队列的性质也有栈的性质。
deque对象创建:deque<typename> que
deque的一些成员函数:

函数名功能
push_back()队尾入队
push_front()队首入队
pop_front()队首元素出队
pop_back()队尾元素出队
empty()判断队列是否为空
front()返回队首元素
back()返回队尾元素

入队操作:

	while(!que.empty()&&que.back()>value)que.pop_back();
	que.push_back(value);//value 为要入队的元素

如果要维护长度的话另加操作

手写实现:

#include<iostream>
using namespace std;
const int MAX_N=1e4; 	//确保大小够用 
int que[MAX_N],head=0,tail=0;		//队首队尾指针,队列大小即为 tail-head 
int main()
{
	int arr[10]={135,6,4,9,7,1,6,3,8,8};
	for(int i=0;i<10;i++)
	{
		if(i>=3&&que[head]==arr[i-3])head++;	//头后移,出队 
		while(head<tail&&que[tail-1]>arr[i])tail--;	//队尾前移,出队 
		que[tail++]=arr[i];	//入队
		cout<<que[head]<<" ";
	} 
	return 0;
}

经典例题:P1440 求m区间内的最小值

题解:

#include<iostream>
#include<cstdio>
using namespace std;
const int MAX_N=2e6+1;
int arr[MAX_N];
int que[MAX_N],head=0,tail=0; 
inline int read()
{
	int sum=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){sum=(sum<<1)+(sum<<3)+c-48;c=getchar();}
	return sum*f;
}
inline void write(int x)
{
    char ch[20];
    int len=0;
    if(x<0)
      {
        putchar((1<<5)+(1<<3)+(1<<2)+1);
        x=~x+1;
      }
    do 
      {
        ch[len++]=x%10+(1<<4)+(1<<5);
        x/=10;
      }while(x>0);
    for(int i=len-1;i>=0;i--) 
       putchar(ch[i]);
    return ;
} 
int main()
{
	int n=read(),m=read();
	cout<<0<<endl;
	for(int i=0;i<n-1;i++)
	{
		arr[i]=read();
		if(i>=m&&que[head]==arr[i-m])head++;
		while(head!=tail&&arr[i]<que[tail-1])tail--;
		que[tail++]=arr[i];
		write(que[head]);
		putchar('\n');
	}
	return 0;
}
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值