我们主打的就是一个单调队列
解题步骤与解释都放在注释里面了,几乎每一步都有注释
希望我的注释可以对你有所帮助!
#include <iostream>
#include <deque>
using namespace std;
const int N = 1000005;
int a[N];
deque<int>q; // 队列中的数据实际上是元素在元序列中的位置
int main()
{
int n, m;
cin >> n >> m;
// n是所有的数的个数,m是窗口的大小
for (int i = 0; i < n; i++)
{
cin >> a[i];// 把数字都输进去
}
// 下面开始用单调队列来把每一个窗口里面的最小的数输出出来
for (int i = 0; i < n; i++)
{
while (!q.empty() && a[q.back()] > a[i])
{
q.pop_back();
// 每当窗口放进去一个新的值之前
// 要把这个要新加入的值和我们单调队列的队尾的值相比较
// 如果队尾的值没有这个值大,那么便ok,如果队尾的值确实比这个值大,那就把队尾pop
// 接着将这个要加入的值与新的队尾进行比较,知道队尾不用在pop之后,便停止(或者把整个单调队列的值都pop完)
}
q.push_back(i); // 插入新的值
// 上面的操作让我们实现了队列的单调性,那么下面我们来实现“窗口”
if (i >= m-1) // 避免了一开始窗口还不成型
{
while (!q.empty() && q.front() <= i - m) // 注意这里的不等号是小于等于!!!
{
// 那么为什么是i-m?
// 我们要理解,我们的单调序列绝对不是我们的窗口
// 这个题实际上就没有窗口
q.pop_front();
// 这个操作是为了保证当前输出的最小值是当前窗口的最小值!!!!
// 是这样的,每个窗口里面的最左边的值的下标就是i-m
// 我们这样做是为了把不是这个窗口的数的下标排出去,以防止输出不是当前窗口的数
}
cout << a[q.front()] << ' ';
}
}
// 我们输出完了最小值,再输出最大值
cout << '\n';
// 我们先清理一下我们的单调序列
q.clear();
// 建立for循环,开始往单调序列里面放下标
for (int i = 0; i < n; i++)
{
while (!q.empty() && a[q.back()] < a[i])
{
q.pop_back(); // 之前是把小的放前面,现在是把大的放前面
}
q.push_back(i);
if (i >= m-1) // 窗口已经成型,那就可以开始输出了
{
while (!q.empty() && q.front() <= i - m) // 注意这里的不等号是小于等于!!!
{
q.pop_front();
}
cout << a[q.front()] << ' ';
}
}
cout << '\n';
return 0;
}