【数据结构】队列应用-单调队列

一、题干:acwing单调队列

二、思路

        按照惯例,先想暴力做法。每移动一次窗口遍历一次窗口内元素,记录最值,时间复杂度O(nk)。

        那么该怎么优化呢,遍历n次窗口肯定没办法减少,那就只能从搜索窗口内最值元素的速度入手了。

        很自然的就能想到,如果我们让窗口内的元素排好序,那么搜索的时候只要输出端点值就好了。可这还有几个问题,窗口内的元素会变化,总不能变化一次排序一次吧,那也太花时间了。

        能不能让窗口内的元素变化的时候就自动排序好呢?

        欸!单调队列恰好能解决这个问题。我们每一次变化的时候,先把不在窗口内的那个元素删掉,然后加入新元素的时候我们动一些小手段,我们把队列内比新元素大的全部丢掉,这样子整个队列从左到右就保持了递增的单调性,左端点一定最小且在窗口内。我知道你可能担心什么,万一我们把之后的最值丢掉了怎么办?不会的,因为比新元素大的值会比新元素更早出队,他们没有机会从新元素手里拿走最小值的称号了。输出最大值的时候我们只需要把这个过程对称着再做一遍就好了。

三、代码实现

#include<iostream>

using namespace std;

const int N = 1e6 + 10;

int a[N],q[N];

int main()
{
	int n,k;
	cin>>n>>k;
	for(int i = 0; i < n; i ++ ) cin>>a[i];
	
	int hh = 0, tt = -1;
	for(int i = 0; i < n; i ++ )
	{
		if(hh <= tt && q[hh] < i - k + 1) hh ++;
		while(hh <= tt && a[i] <= a[q[tt]]) tt --;
		q[++ tt] = i; 
		if(i >= k - 1) cout << a[q[hh]]<<' ';
	}
	
	cout<<'\n';
	
	hh = 0, tt = -1;
	for(int i = 0; i < n; i ++ )
	{
		if(hh <= tt && q[hh] < i - k + 1) hh ++;
		while(hh <= tt && a[i] >= a[q[tt]]) tt --;
		q[++ tt] = i; 
		if(i >= k - 1) cout << a[q[hh]]<<' ';
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值