题目传送门

一、题目描述

有一个大小为\(k\)的滑动窗口,它从数组的最左边移动到最右边。

您只能在窗口中看到\(k\)个数字。

每次滑动窗口向右移动一个位置。

以下是一个例子:

该数组为\([1 \ \ 3\ \ -1\ \ -3\ \ 5\ \ 3\ \ 6\ \ 7]\)\(k\)为3。

窗口位置 最小值 最大值
[\(1\) \(3\) \(-1\)] \(-3\) \(5\) \(3\) \(6\) \(7\) \(-1\) \(3\)
\(1\) [\(3\) \(-1\) \(-3\)] \(5\) \(3\) \(6\) \(7\) \(-3\) \(3\)
\(1\) \(3\) [\(-1\) \(-3\) \(5\)] \(3\) \(6\) \(7\) \(-3\) \(5\)
\(1\) \(3\) \(-1\) [\(-3\) \(5\) \(3\)] \(6\) \(7\) \(-3\) \(5\)
\(1\) \(3\) \(-1\) \(-3\) [\(5\) \(3\) \(6\)] \(7\) \(3\) \(6\)
\(1\) \(3\) \(-1\) \(-3\) \(5\) [\(3\) \(6\) \(7\)] \(3\) \(7\)

您的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

二、理解和感悟

下面以求窗口中最小值为例,进行说明:

1、维护一个队列,来一个新人,将队列中大于它的老家伙们干死,保留比它小的老家伙们。

2、道理:
(1)老家伙比新人还大,新人又小活的时间又长,老家伙永远也不可能为后面提供帮助了,所以干死~
tt--
(2)不管是不是更小,只要寿命到了,也一样要死。
hh++

3、其实,这本身是一个双端队列,不是传统的队列,出队的可能是队头,也可能是队尾。

求窗口中的最大值正好与之相反,小修改一下即可。

三、C++代码

#include <bits/stdc++.h>

using namespace std;
const int N = 1000010;
int n; //数组长度
int k; //窗口长度
int a[N]; //原始数组
int q[N]; //队列,内容是原始数组的下标

int main() {
    //优化输入
    ios::sync_with_stdio(false);
    //读入数据
    cin >> n >> k;
    for (int i = 1; i <= n; i++)cin >> a[i];

    //从左至右,每个位置滑动窗口中的最小值。
    int tt = -1, hh = 0;
    for (int i = 1; i <= n; i++) {
        //队列中数据有两种方式死亡:
        //1、到年龄了,该死了。
        if (hh <= tt && i + 1 - k > q[hh]) hh++;
        //2、没到年龄,但有后面的小孩比你牛,活的还比你长,岁数大的就没有保存下去的必要了,死了得了。
        while (hh <= tt && a[q[tt]] >= a[i]) tt--;
        //加入队伍
        q[++tt] = i;
        //窗口够长后,才能输出窗口内最小值,队头就是最小值。(单调队列)
        if (i >= k) printf("%d ", a[q[hh]]);
    }

    //输出换行
    puts("");

    //从左至右,每个位置滑动窗口中的最大值。
    tt = -1, hh = 0;
    for (int i = 1; i <= n; i++) {
        if (hh <= tt && i + 1 - k > q[hh]) hh++;
        while (hh <= tt && a[q[tt]] <= a[i]) tt--;
        q[++tt] = i;
        if (i >= k) printf("%d ", a[q[hh]]);
    }
    return 0;
}

相关文章:

猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-11-01
相关资源
相似解决方案