https://www.acwing.com/problem/content/156/
以找最小的为例子:
q[N] : 存放单调递增的序列下标 ,模拟单调队列, hh为较小的队头,每次输出,则输出 a[ q[ hh] ]
当所要维护的窗口的起点超过hh,即单调队列的头元素时,hh++ ,让头更新;因为q数组存放的一定是单调递增的, 所以每次输出 q[ hh ]一定是窗口中最小的。
?关于为什么要 i - k + 1 >= q[ hh ]
q 放的下标对应的数一定是单调递增的,当窗口后移时,hh可能已经滑出窗口了,由于每轮只添加一个元素,所以用 if 。这样q数组就起到一个预先处理的效果。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, k;
int a[N] ,q[N];//q序列用于存放一个单调递增的队列, i控制它的范围
int main()
{
cin >> n >> k;
for(int i = 0; i < n; i ++) cin >> a[i];
int hh = 0, tt = -1;
//找最小
//起点i - k + 1 终点i
for( int i = 0; i < n; i ++){
if(hh <= tt && i - k + 1 > q[hh]) hh ++;//队头滑出窗口,更新队头
while( hh <= tt && a[q[tt]] >= a[i]) tt --;//队尾元素不要比当前的大,否则弹出
q[ ++tt ] = i;//当前元素下标进入队列
if(i >= k - 1) printf("%d ", a[q[hh]]);//维护到k个区间时 可以开始输出
}
puts("");
//找最大
hh = 0, tt = -1;
//起点i - k + 1 终点i
for( int i = 0; i < n; i ++){
if(hh <= tt && i - k + 1 > q[hh]) hh ++;//队头滑出窗口,更新队头
while( hh <= tt && a[q[tt]] <= a[i]) tt --;//队尾元素不要比当前的大,否则弹出
q[ ++tt ] = i;//当前元素下标进入队列
if(i >= k - 1) printf("%d ", a[q[hh]]);
}
return 0;
}