【代码超详解】POJ 2823 Sliding Window(单调队列 + 快读快写(读写挂),829 ms)

一、题目描述

Sliding Window

Time Limit: 12000MS Memory Limit: 65536K
Total Submissions: 84160 Accepted: 23627(2020/2/5 15:21)
Case Time Limit: 5000MS

Description

An array of size n ≤ 106 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example:
The array is [1 3 -1 -3 5 3 6 7], and k is 3.

在这里插入图片描述
Your task is to determine the maximum and minimum values in the sliding window at each position.

Input

The input consists of two lines. The first line contains two integers n and k which are the lengths of the array and the sliding window. There are n integers in the second line.

Output

There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values.

Sample Input

8 3
1 3 -1 -3 5 3 6 7

Sample Output

-1 -3 -3 -3 3 3
3 3 5 5 6 7

Source

POJ Monthly–2006.04.28, Ikki

二、算法分析说明与代码编写指导

通过 STL 的 deque 可以构造一个单调队列,队列从头到尾是严格递增或递减的。
单调队列总是从队尾入列,队首和队尾都可以出列。单调队列用于求滑动窗口的最大值。
单调 (递增) 队列可以用来求滑动窗口的最小值。同理,单调 (递减) 队列可以用来求滑动窗口的最大值。
维护单调队列的方法是:

单调队列建立以后,要先放入一个元素。这样可以避免后续步骤中取空队列的尾部的值而报错。
滑动窗口的大小(长度)一般是给定的。这里以维护单调增队列为例,先向队列中添加元素,直到添加次数(为防止取空队列的尾部的值而
事先放入的第一个元素记为添加1次)达到窗口长度。在插入新元素之前,为了确保队列的单调性,要先检查队尾是否有比准备插入的元素大
的元素。如果有,就要不断弹出队尾,直到队尾的元素小于待插入的元素。如果没有,则直接添加。这样得到的队列显然是单调的。
添加次数达到窗口长度后,在接下来的添加过程中,在弹出队尾之前要额外增加一步:检查队首元素是否已经离开窗口的左端。如果是,弹出
队首。接下来再执行上述添加步骤。
为了实现队首元素的及时弹出,这里将元素本身和元素在数组中的位置(下标)一并存入队列。只要队列中与队首元素一起保存的该元素的位置
已经脱离了窗口左端(添加次数 - 元素 位置 >= 窗口长度),就弹出队首。

本题采用 scanf 和 printf 进行读写会超时,所以采用快读和快写。readi、readu、writei 分别为读入有符号整数、读入无符号整数、输出有符号整数的快速输入输出函数。delim 为输出时的分隔符。

三、AC 代码

#include<cstdio>
#include<deque>
#include<map>
#include<algorithm>
#include<cctype>
#pragma warning(disable:4996)
using namespace std;
unsigned n, k, k0; deque<pair<int, unsigned> > q; int a[1000000]; pair<int, unsigned> p;
template<class _Ty> inline void readi(_Ty& x) {
	static _Ty c, s; x = 0, s = 1;
	c = getchar();
	if (c == '-')s = -1;
	else x = (x << 3) + (x << 1) + c - '0';
	for (;;) {
		c = getchar();
		if (!isdigit(c))break;
		x = (x << 3) + (x << 1) + c - '0';
	}
	x *= s;
}
template<class _Ty> inline void readu(_Ty& x) {
	static _Ty c; x = 0;
	for (;;) {
		c = getchar();
		if (!isdigit(c))return;
		x = (x << 3) + (x << 1) + c - '0';
	}
}
template<class _Ty> inline void writei(_Ty x, const char& delim) {
	static char c[64];
	unsigned p = 0;
	if (x < 0) { putchar('-'), x = -x; }
	if (x == 0) { putchar('0'); putchar(delim); return; }
	while (x) { c[++p] = x % 10 + '0', x /= 10; }
	while (p) { putchar(c[p]); --p; }
	putchar(delim);
}
int main() {
	readu(n); readu(k); k0 = k - 1;
	for (unsigned i = 0; i < n; ++i)readi(a[i]);
	p = { a[0],0 }; q.push_back(p);
	for (unsigned i = 1; i < k0; ++i) {
		while (q.empty() == false && a[i] <= q.back().first)q.pop_back();
		p = { a[i],i }; q.push_back(p);
	}
	for (unsigned i = k0; i < n; ++i) {
		if (i - q.front().second >= k)q.pop_front();
		while (q.empty() == false && a[i] <= q.back().first)q.pop_back();
		p = { a[i],i }; q.push_back(p); writei(q.front().first, ' ');
	}
	putchar('\n'); q.clear();
	p = { a[0],0 }; q.push_back(p);
	for (unsigned i = 1; i < k0; ++i) {
		while (q.empty() == false && a[i] >= q.back().first)q.pop_back();
		p = { a[i],i }; q.push_back(p);
	}
	for (unsigned i = k0; i < n; ++i) {
		if (i - q.front().second >= k)q.pop_front();
		while (q.empty() == false && a[i] >= q.back().first)q.pop_back();
		p = { a[i],i }; q.push_back(p); writei(q.front().first, ' ');
	}
	putchar('\n');
	return 0;
}
发布了214 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/COFACTOR/article/details/104183245