ac 154. 滑动窗口
如果用普通窗口 每一次往右边移动一格(时间n)进行一次判断(时间k)需要 nk 的时间复杂度
用排序好的窗口, 比如一开始输入
8 3
1 3 -1 -3 5 3 6 7
先是 1 这个数字再窗口内, 然后 由于第二个数字 3比1要小所以不记录队列中
再是 -1 这个数字 比1小所以记录 此时队列为 [1 ,-1](当然是用数组的下标来标记实际上是 [0, 1]
再下一个数字同理 1, -1, -3
再下一个数字 此时 由于大于 了窗口长度 所以先把 1 去除 变成 [-1, -3](实际[1, 2])
再比较 5 这个数字 由于比-3要大所以不记录,如此一直比较。
当i的大小大于窗口长度就可以开始输出了
输出最大值同理
// 常见模型:找出滑动窗口中的最大值/最小值
// int hh = 0, tt = -1;
// for (int i = 0; i < n; i ++ )
// {
// while (hh <= tt && check_out(q[hh])) hh ++ ; // 判断队头是否滑出窗口
// while (hh <= tt && check(q[tt], i)) tt -- ;
// q[ ++ tt] = i;
// }
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int q[N], a[N];
int main() {
int n, k;
cin >> n >> k;
for (int i = 0; i < n; i ++) {
cin >> a[i];
}
int hh = 0, tt = -1;
// i 本质是窗口的依次经历的右端点
for (int i = 0; i < n; i ++ )
{
// 当前窗口区间是[i - k + 1, i]
if (hh <= tt && q[hh] < i - k + 1) hh ++; //队首小于当前窗口最左边就舍去
while (hh <= tt && a[q[tt]] >= a[i]) tt -- ; //队尾(左为首,右为尾)大于当前的元素,那么他一定不会被当成最小值输出,就删掉
q[ ++ tt] = i;//再加当前的数字
if(i >= k - 1) printf("%d ", a[q[hh]]);
}
puts("");
hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
if (hh <= tt && q[hh] < i - k + 1) hh ++;
while (hh <= tt && a[q[tt]] <= a[i]) tt -- ;
q[ ++ tt] = i;
if(i >= k - 1) printf("%d ", a[q[hh]]);
}
puts("");
return 0;
}