【POJ2823】单调队列

本文介绍了一种使用单调队列解决滑动窗口中最大最小值问题的算法。通过维护两个单调队列,分别找到窗口内的最大值和最小值,实现高效求解。文章详细解释了单调队列的工作原理,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.题目链接。题意:给一个数组和一个长度k,询问从k到n,每个长度为k的小区间,输出区间(i-k,i)这个区间的最大最小值。

2.分析:这是一个滑窗的裸题,我们采用单调队列解决它。单调队列听名字就知道它是单调的了,就是我们基本的队列的延申,一般是一个双端的队列,可以从尾部入队,两端都可以出队。我们看待这个问题,就相当于有一个窗口大小为k,在数组上滑动。也叫做滑动窗口。通过这个滑窗,我们可以找到这一段的最值。

3.单调队列怎么写,应该没啥好说的。就是使用数组模拟一下就行了。我们只看单调增的写法:每输入一个元素,我们与对位比较,如果比队尾大,那么这个队尾没啥用,舍弃。直到找到一个比当前元素小的,停止操作,记录这个下标。就简单的完成了这个操作。写完单调队列之后,问题就解决了。不顾一般来说单调队列很少直接考,都是使用单调队列来优化一些算法,比如优化DP/dfs等。最后附上AC的代码:


#include<iostream>
#include<stdio.h>
using namespace std;
int n, k;
const int N = 1e6 + 10;
int maxq[N], minq[N], num[N];
int maxans[N], minans[N];
#pragma warning(disable:4996)
int main()
{
	while (~scanf("%d%d", &n, &k))
	{

		int maxhead = 0, maxtail = 0;
		int minhead = 0, mintail = 0;
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &num[i]);
			//维护最大值:单调增的队列
			if (maxhead<maxtail && maxq[maxhead] <= i - k) maxhead++;
			while (maxhead<maxtail && num[maxq[maxtail - 1]] <= num[i]) maxtail--;
			maxtail++;
			maxq[maxtail - 1] = i;
			maxans[i] = num[maxq[maxhead]];
			//维护最小值:单调减的队列
			if (minhead<mintail && minq[minhead] <= i - k) minhead++;
			while (minhead<mintail && num[minq[mintail - 1]] >= num[i]) mintail--;
			mintail++;
			minq[mintail - 1] = i;
			minans[i] = num[minq[minhead]];
		}
		for (int i = k - 1; i < n; i++)cout << minans[i] << " "; cout << endl;
		for (int i = k - 1; i < n; i++)cout << maxans[i] << " "; cout << endl;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值