AcWing 154. 滑动窗口
原题链接
简单
作者:
NCpaste
,
2023-05-25 15:35:35
,
所有人可见
,
阅读 21
思路
- 维护两个单调队列
- 最大值:只要大的,小的不要,所以遇到比自己小的就删掉(出栈),
rr--
;
- 最小值:只要小的,大的不要,所以遇到比自己大的就删掉(出栈),
rr--
;
- 如何维护窗口边界
- 左边界用
i-k+1
和当前存储的单调队列左边界相比较,如果单调队列不在窗口内了,ll++
,因为是一个一个读的,所以边界判断一次即可
- 单调队列怎么定义的
- 这里跟y总定义的一样,单调队列的左边界为最值,以最小值举例,最小的一定在最左边
- 有没有可能中间出现一个最小的,可能,此时就会将原来的左边界吞掉,也就是
rr--
,因为最值需要一个就够了,
- 单调队列会不有
3 1 2
的情况出现,不会,因为读到2之前,1就会把3吞掉
- 右边界就是
rr
维护,通常用不到维护,因为单调栈的右边界<=窗口的右边界(都是i
顺着读的,总不能超出去)
注意
- 输出的时候
i>=k-1
的时候才开始输出
- 最大最小改个符号
- 注意更新的时候等号的处理,这里等号应该是留下的
代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e6 + 10;
int a[N], ind[N];
int n, k;
int main ()
{
cin >> n >> k;
for (int i = 0; i < n; i ++)
{
cin >> a[i];
}
int ll, rr;
ll = rr = 0;
for (int i = 0; i < n; i ++)
{
if (ll < rr && ind[ll] < i-k+1) ll ++;
while (ll < rr && a[i] < a[ind[rr-1]]) rr --;
ind[rr++] = i;
if (i >= k-1)
cout << a[ind[ll]] << " ";
}
cout << endl;
memset(ind, 0, sizeof ind);
ll = rr = 0;
for (int i = 0; i < n; i ++)
{
if (ll < rr && ind[ll] < i-k+1) ll ++;
while (ll < rr && a[i] > a[ind[rr-1]]) rr --;
ind[rr++] = i;
if (i >= k-1)
cout << a[ind[ll]] << " ";
}
cout << endl;
return 0;
}