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;
}