给定一个大小为 n≤1e6 的数组。
有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边。
你只能在窗口中看到 k 个数字。
每次滑动窗口向右移动一个位置。
输出格式
输出包含两个。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。
/*
单调队列
保证了数组每个元素最多进队列一次,时间复杂度为O(n);
局部单调最终整体单调,保持队头是当前窗口中最小的元素
*/
# include <iostream>
using namespace std;
const int N = 1e6 + 10;
// a[N]:原数组
// q[N]:原数组元素的下标
// hh:队头
// tt:队尾
int a[N], q[N], hh = 0, tt = -1;
int main()
{
int n, k;
cin >> n >> k;
for (int i = 0; i < n; ++ i)
{
// 局部单调变成整体单调
// 变成严格单调递增的队列,队头在左边,队尾在右边
scanf("%d", &a[i]);
if (i - k + 1 > q[hh]) ++ hh; // 队头出窗口,hh加1
// 新插入的元素比当前队尾的元素小
while (hh <= tt && a[i] <= a[q[tt]]) -- tt; // 队尾不单调,tt减1
q[++ tt] = i; // 下标加到队尾
if (i - k + 1 >= 0) printf("%d ", a[q[hh]]); // 输出结果
}
cout << endl;
// 算最大值前注意将hh和tt重置;
hh = 0; tt = -1;
for (int i = 0; i < n; ++ i)
{
if (i - k + 1 > q[hh]) ++ hh;
while (hh <= tt && a[i] >= a[q[tt]]) -- tt;
q[++ tt] = i;
if (i - k + 1 >= 0) printf("%d ", a[q[hh]]);
}
return 0;
}