POJ 2823 Sliding Window + 单调队列
一、概念介绍
1、 双端队列
双端队列是一种线性表,是一种特殊的队列,遵守先进先出的原则。双端队列支持以下4种操作:
- (1) 从队首删除
- (2) 从队尾删除
- (3) 从队尾插入
- (4) 查询线性表中任意一元素的值
2、 单调队列
单调队列是一种特殊的双端队列,其内部元素具有单调性。最大队列与最小队列是两种比较常用的单调队列,其内部元素分别是严格单调递减(不是非递增)和严格单调递增(不是非递减)的。
单调队列的常用操作如下:
- (1) 插入:若新元素从队尾插入后会破坏单调性,则删除队尾元素,直到插入后不再破坏单调性为止,再将其插入单调队列。
- (2) 获取最优(最大、最小)值:访问队首元素
以下是一个单调递增队列的例子:
队列大小不能超过3,入队元素依次为3,2,8,4,5,7,6,4
3入队:(3)
3从队尾出队,2入队:(2)
8入队:(2,8)
8从队尾出队,4入队:(2,4)
5入队:(2,4,5)
2从队头出队,7入队:(4,5,7)
7从队尾出队,6入队:(4,5,6)
6从队尾出队,5从队尾出队,4从队尾出队,4入队:(4)
以上左端为队头,右端为队尾。
二、单调队列的应用
1、最大值的维护:
比如我们要维护一个区间为k的最大值的单调队列,由于新插入 的节点他的“生命力”肯定比原先已经在队列中的元素“活”的时间长,将插入元素不断与队尾元素比, 如果他大于队尾元素,那么tail--将队尾元素删掉,(因为目前插入的这个元素值(设为pos)更大,而且“活”的时间 长,有pos在,队尾元素的有“生”之年永远都没法为最大值,故而直接无视比pos小的队尾了)。直到对空位置或者 找到了一个比pos大的队尾。
2、poj 2823 Sliding Window
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.
Window position | Minimum value | Maximum value |
---|---|---|
[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 |
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
思路
一、
这道题目有个非常重要的信息,即所有的区间都是等长且连续的,那么对于“相邻”两个区间(l,r)与(l+1,r+1)有些极优美的性质:al,al+1,al+2,…,ar-1,ar,ar+1,以最大值为例:我们注意到,在区间(l,r)中,Max(al,al+1,al+2,…,ar-1,ar)=max(al,max(al+1,al+2,…,ar-1,ar))
在区间(l+1,r+1)中,Max(al+1,al+2,…,ar-1,ar,ar+1)=max(max(al+1,al+2,…,ar-1,ar),ar+1)
两个式子中有相同的部分max(al+1,al+2,…,ar-1,ar),经验告诉我们,区间(l,r)中最大值落在(l+1,r)区间的概率很大。那么,在求(l+1,r+1)的最值时,我们完全没有必要再扫描一次。只有当上一次的最大值落在了al上时才需要重新扫描,这样,算法得到了极大的优化。
继续考虑这样一个问题,以最大值为例,对于任意l<=i<=j<=r,如果ai<aj,那么,在区间向右移动的过程中,最大值永远也不会落在ai上,因为ai比aj先失效,能用ai一定能用aj,此时我们便不再需要ai了。这个性质与单调队列性质重合了。在扫描这个数列的时候,我们维护一个单调递减的队列。当我们将区间从(l,r)移动到(l+1,r+1)时,将ar+1 插入单调队列,若队首元素不在(l+1,r+1)时,删除它。这样处理后的队首元素便是(l+1,r+1)区间中的最大值。
二、
看这个问题: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.Your task is to determine the maximum and minimum values in the sliding window at each position.
也就是有一个数列a,要求你求数列b和c,b[i]是a[i]…a[i+w-1]中的最小值,c[i]是最大值。如果a是1,3,-1,-3,5,3,6,7,则b为-1,-3,-3,-3,3,3,c为3,3,5,5,6,7。
这个问题相当于一个数据流(数列a)在不断地到来,而数据是不断过期的,相当于我们只能保存有限的数据(sliding window中的数据,此题中就是窗口的宽度w),对于到来的查询(此题中查询是每时刻都有的),我们要返回当前滑动窗口中的最大值最小值。注意,元素是不断过期的。
解决这个问题可以使用一种叫做单调队列的数据结构,它维护这样一种队列:
- a)从队头到队尾,元素在我们所关注的指标下是递减的(严格递减,而不是非递增),比如查询如果每次问的是窗口内的最小值,那么队列中元素从左至右就应该递增,如果每次问的是窗口内的最大值,则应该递减,依此类推。这是为了保证每次查询只需要取队头元素。
- b)从队头到队尾,元素对应的时刻(此题中是该元素在数列a中的下标)是递增的,但不要求连续,这是为了保证最左面的元素总是最先过期,且每当有新元素来临的时候一定是插入队尾。
满足以上两点的队列就是单调队列,首先,只有第一个元素的序列一定是单调队列。
那么怎么维护这个单调队列呢?无非是处理插入和查询两个操作。
对于插入,由于性质b,因此来的新元素插入到队列的最后就能维持b)继续成立。但是为了维护a)的成立,即元素在我们关注的指标下递减,从队尾插入新元素的时候可能要删除队尾的一些元素,具体说来就是,找到第一个大于(在所关注指标下)新元素的元素,删除其后所有元素,并将新元素插于其后。因为所有被删除的元素都比新元素要小,而且比新元素要旧,因此在以后的任何查询中都不可能成为答案,所以可以放心删除。
对于查询,由于性质b,因此所有该时刻过期的元素一定都集中在队头,因此利用查询的时机删除队头所有过期的元素,在不含过期元素后,队头得元素就是查询的答案(性质a),将其返回即可。由于每个元素都进队出队一次,因此摊销复杂度为O(n)。
#include<stdio.h> #include<string.h> const int maxn = 1000005; int a[maxn],q[maxn]; int n,k; void Monotonequeue(int op) { memset(q,0,sizeof(q)); bool first = true; int head = 1,tail = 0; for (int i = 1; i <= n; i++) { while (head <= tail && ((!op && a[i] <= a[q[tail]]) || (op && a[i] >= a[q[tail]]))) tail--; q[++tail] = i; while (head <= tail && q[tail] - q[head] >= k) head++; if (i >= k) first?printf("%d",a[q[head]]):printf(" %d",a[q[head]]),first = false; } printf("\n"); } int main() { scanf("%d%d",&n,&k); for (int i = 1; i <= n; i++) { scanf("%d",&a[i]); } Monotonequeue(0); //维护单调递增队列,队头元素最小 Monotonequeue(1); //维护单调递减队列,队头元素最大 return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef __int64 LL; const int maxn = 1000005; struct node { int pos,val; } q[maxn]; int num[maxn],n,k; int Min[maxn]; int Max[maxn]; void getMin() { int head=1,tail=0; for(int i=1; i<k; i++) { //前k-1个数跟查询无关,直接放进来 while(head<=tail&&num[i]<q[tail].val) tail--; //插入的准备操作,要么队列为空,要么找到一个位置使得符合单调队列定义 tail++; q[tail].val=num[i]; q[tail].pos=i; //插入 } for(int i=k; i<=n; i++) { while(head<=tail&&num[i]<q[tail].val) tail--; tail++; q[tail].val=num[i]; q[tail].pos=i; while(i-q[head].pos>=k) head++; //删除操作,维护最大的区间长度 Min[i-k]=q[head].val; //答案记录 } } void getMax() { int head=1,tail=0; for(int i=1; i<k; i++) { while(head<=tail&&num[i]>q[tail].val) tail--; tail++; q[tail].val=num[i]; q[tail].pos=i; } for(int i=k; i<=n; i++) { while(head<=tail&&num[i]>q[tail].val) tail--; tail++; q[tail].val=num[i]; q[tail].pos=i; while(i-q[head].pos>=k) head++; Max[i-k]=q[head].val; } } int main() { while(scanf("%d%d",&n,&k)!=EOF) { for(int i=1; i<=n; i++) scanf("%d",&num[i]); getMin(); for(int i=0; i<=n-k; i++) printf("%d%c",Min[i],i==n-k?'\n':' '); getMax(); for(int i=0; i<=n-k; i++) printf("%d%c",Max[i],i==n-k?'\n':' '); } return 0; }
POJ 2823 Sliding Window + 单调队列的更多相关文章
- poj 2823 Sliding Window (单调队列入门)
/***************************************************************** 题目: Sliding Window(poj 2823) 链接: ...
- POJ 2823 Sliding Window (单调队列)
单调队列 加了读入挂比不加更慢.... 而且这份代码要交c++ 有大神G++跑了700ms..... orzorzorz #include<iostream> #include<cs ...
- poj 2823 Sliding Windows (单调队列+输入输出挂)
Sliding Window Time Limit: 12000MS Memory Limit: 65536K Total Submissions: 73426 Accepted: 20849 ...
- POJ 2823 Sliding Window 题解
POJ 2823 Sliding Window 题解 Description An array of size n ≤ 106 is given to you. There is a sliding ...
- 洛谷P1886 滑动窗口(POJ.2823 Sliding Window)(区间最值)
To 洛谷.1886 滑动窗口 To POJ.2823 Sliding Window 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每 ...
- POJ 2823 Sliding Window(单调队列入门题)
Sliding Window Time Limit: 12000MS Memory Limit: 65536K Total Submissions: 67218 Accepted: 190 ...
- POJ 2823 Sliding Window 【单调队列】
题目链接:http://poj.org/problem?id=2823 题目大意:给出一组数,一个固定大小的窗体在这个数组上滑动,要求出每次滑动该窗体内的最大值和最小值. 这就是典型的单调队列,单调队 ...
- 【单调队列】poj 2823 Sliding Window
http://poj.org/problem?id=2823 [题意] 给定一个长度为n的序列,求长度为k的滑窗内的最大值和最小值 [思路] 裸的单调队列 注意用C++提交,不然会T,orz我用G++ ...
- 题解报告:poj 2823 Sliding Window(单调队列)
Description An array of size n ≤ 106 is given to you. There is a sliding window of size k which is m ...
随机推荐
- C# FTP上传
public class FtpHelper { public FtpHelper(string p_url, string p_user, string p_password) { if (!p_u ...
- ASP.NT运行原理和页面生命周期详解及其应用
ASP.NT运行原理和页面生命周期详解及其应用 1. 下面是我画的一张关于asp.net运行原理和页面生命周期的一张详解图.如果你对具体不太了解,请参照博客园其他帖子.在这里我主要讲解它的实际应用. ...
- 最佳实践 —— 详细谈谈如何减小APK体积
转载请注明出处: http://www.cnblogs.com/soaringEveryday/p/5254520.html 随着Android移动开发的需求越来越复杂,我们不可避免的遇到发布出去的a ...
- canvas 2d 贴图技术实践
最近在公司内部的技术协会论坛里闲逛的时候,无意中发现了一篇手淘前端大牛岑安两年前写的博文,讲述了canvas的2d贴图技术.看到后觉得相当神奇.于是就自己实现了一下.不过岑安前辈的那篇博文也只是大概讲 ...
- Python3 windows如何安装模块 setuptools
下载的module解压后里面有setup.py文件,如果打开setup.py文件里面有这段代码: from setuptools import setup ... setup( ... 这种的都需要调 ...
- kmp模板,线性完成pos
var p:..] of longint; i,j:longint; a,b:ansistring; begin readln(a); readln(b); P[]:=; j:=; to length ...
- eclipse中的常用插件
常用插件整理: http://blog.sina.com.cn/s/blog_60b5e13e0102vz6q.html 插件带有链接 http://blog.csdn.net/kagoy/ar ...
- __getattr__与__getattribute__
class Foo: def __init__(self,x): self.x=x def __getattr__(self, item): print("执行的是我----->&qu ...
- mysql中insert into select from的使用
如何在mysql从多个表中组合字段然后插入到一个新表中,通过一条sql语句实现.具体情形是:有三张表a.b.c,现在需要从表b和表c中分别查几个字段的值插入到表a中对应的字段.对于这种情况,我们可以使 ...
- 线性表的顺序存储结构C语言版
#include <stdio.h> #define MAXSIZE 101 #define N 10 typedef struct SeqList { int data[MAXSIZE] ...