Files
python/TangDou/AcWing/Queue/154.md
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

90 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

##[$AcWing$ $154$ 滑动窗口](https://www.acwing.com/problem/content/156/)
### 一、题目描述
有一个大小为$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++代码
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
int n;
int k;
int a[N];
int q[N], hh, tt;
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i];
// 初始化队列
hh = 0, tt = -1;
for (int i = 1; i <= n; i++) {
// Q1:队列里面放的是什么?
// A1:是数组下标,是编号,不是值,需要值时,可以通过a[q[hh]]去取值
// Q2:队列的存入形态是什么样的?
// A2: hh....tt,hh在左,tt在右
// Q3:什么样的需要出队列?
// A3: (1)距离当前位置超过窗口范围
// (2) 在窗口范围内,但对后续没有可能发挥作用:区间内的人员,有比你更年轻、更漂亮的,怎么选美也选不到你
while (hh <= tt && i + 1 - k > q[hh]) hh++; // q[hh]:窗口的左起点,hh++:减小窗口长度
while (hh <= tt && a[q[tt]] >= a[i]) tt--; // tt--:减小窗口长度
// q[],hh,tt 三者组成了一个模拟的队列数据结构,对外提供:查询队列中最小值位置的服务q[hh],对内三者互相协作
// 换言之:q[hh]是对外的,hh,tt是数据结构内部概念,不能混淆
q[++tt] = i;
// 只有在区间长度够长的情况下,才能输出区间最小值
if (i >= k) printf("%d ", a[q[hh]]);
}
puts("");
hh = 0, tt = -1;
for (int i = 1; i <= n; i++) {
while (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;
}
```