【题目描述】
给定一个大小为
n
(
n
≤
1
0
6
)
n(n≤10^6)
n(n≤106)的数组。
有一个大小为
k
k
k的滑动窗口,它从数组的最左边移动到最右边。
你只能在窗口中看到
k
k
k个数字。
每次滑动窗口向右移动一个位置。
例如:数组为
[
1
,
3
,
−
1
,
−
3
,
5
,
3
,
6
,
7
]
[1,3,-1,-3,5,3,6,7]
[1,3,−1,−3,5,3,6,7],
k
=
3
k=3
k=3。
【输入格式】
输入一共有两行,第一行有两个正整数
n
,
k
n,k
n,k。第二行
n
n
n个整数,表示序列
a
a
a。
【输出格式】
输出共两行,第一行为每次窗口滑动的最小值,第二行为每次窗口滑动的最大值。
【输入样例】
8 3
1 3 -1 -3 5 3 6 7
【输出样例】
-1 -3 -3 -3 3 3
3 3 5 5 6 7
【分析】
以最小值为例:构造一个单调递增队列
Q
Q
Q,
Q
Q
Q中存数组
a
a
a中元素的下标。
第一次:
Q
=
{
1
}
Q=\left\{1\right\}
Q={1}
第二次:
Q
=
{
1
,
2
}
Q=\left\{1,2\right\}
Q={1,2}
第三次:
Q
=
{
3
}
Q=\left\{3\right\}
Q={3}(因为队列单调递增,
−
1
-1
−1最小,所以挤掉
1
1
1和
3
3
3,找最小值的时候也不会轮到它们)
第四次:
Q
=
{
4
}
Q=\left\{4\right\}
Q={4}(
1
1
1已经在外面了。
−
3
<
−
1
-3<-1
−3<−1果断挤掉)
第五次:
Q
=
{
4
,
5
}
Q=\left\{4,5\right\}
Q={4,5}(
5
>
−
3
5>-3
5>−3可以作为候选人)
第六次:
Q
=
{
4
,
6
}
Q=\left\{4,6\right\}
Q={4,6}(果断挤掉,有比
5
5
5合适的候选人)
第七次:
Q
=
{
6
,
7
}
Q=\left\{6,7\right\}
Q={6,7}(
4
4
4不在范围内,出列)
第八次:
Q
=
{
6
,
7
,
8
}
Q=\left\{6,7,8\right\}
Q={6,7,8}
每次都输出队列中的第一个元素,即为当前窗口中的最小值。求最大值同理,构造单调递减队列即可
【手写队列代码】
#include <iostream>
using namespace std;
const int N = 1000010;
int a[N], Q[N], hh, tt;
int n, k;
int main()
{
cin >> n >> k;
for (int i = 0; i < n; i++) cin >> a[i];
//构造单增队列输出最小值
hh = 0, tt = -1;
for (int i = 0; i < n; i++)
{
if (hh <= tt && i - Q[hh] == k) hh++;//队首元素超出窗口范围时,移除队首元素
while (hh <= tt && a[i] < a[Q[tt]]) tt--;//若待入队元素小于队尾元素,则移除队尾元素,构造单增队列
Q[++tt] = i;
if (i >= k - 1) cout << a[Q[hh]] << ' ';
}
cout << endl;
//构造单减队列输出最大值
hh = 0, tt = -1;
for (int i = 0; i < n; i++)
{
if (hh <= tt && i - Q[hh] == k) hh++;
while (hh <= tt && a[i] > a[Q[tt]]) tt--;
Q[++tt] = i;
if (i >= k - 1) cout << a[Q[hh]] << ' ';
}
return 0;
}
【deque实现代码】
#include <iostream>
#include <deque>
using namespace std;
const int N = 1000010;
int n, k;
int a[N];
deque<int> Q;
int main()
{
cin >> n >> k;
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++)
{
if (Q.size() && i - Q.front() == k) Q.pop_front();
while (Q.size() && a[i] < a[Q.back()]) Q.pop_back();
Q.push_back(i);
if (i >= k - 1) cout << a[Q.front()] << ' ';
}
cout << endl;
Q.clear();
for (int i = 0; i < n; i++)
{
if (Q.size() && i - Q.front() == k) Q.pop_front();
while (Q.size() && a[i] > a[Q.back()]) Q.pop_back();
Q.push_back(i);
if (i >= k - 1) cout << a[Q.front()] << ' ';
}
return 0;
}