[POJ2823] Sliding Window 「单调队列」
我们从最简单的问题开始:
给定一个长度为N的整数数列a(i),i=0,1,...,N-1和窗长度k.
要求:
f(i) = max{ a(i-k+1),a(i-k+2),..., a(i) },i = 0,1,...,N-1
问题的另一种描述就是用一个长度为k的窗在整数数列上移动,求窗里面所包含的数的最大值。
解法一:
很直观的一种解法,那就是从数列的开头,将窗放上去,然后找到这最开始的k个数的最大值,然后窗最后移一个单元,继续找到k个数中的最大值。
这种方法每求一个f(i),都要进行k-1次的比较,复杂度为O(N*k)。
那么有没有更快一点的算法呢?
解法二:
我们知道,上一种算法有一个地方是重复比较了,就是在找当前的f(i)的时候,i的前面k-1个数其它在算f(i-1)的时候我们就比较过了。那么我们能不能保存上一次的结果呢?当然主要是i的前k-1个数中的最大值了。答案是可以,这就要用到单调递减队列。
单调递减队列是这么一个队列,它的头元素一直是队列当中的最大值,而且队列中的值是按照递减的顺序排列的。我们可以从队列的末尾插入一个元素,可以从队列的两端删除元素。
1.首先看插入元素:为了保证队列的递减性,我们在插入元素v的时候,要将队尾的元素和v比较,如果队尾的元素不大于v,则删除队尾的元素,然后继续将新的队尾的元素与v比较,直到队尾的元素大于v,这个时候我们才将v插入到队尾。
2.队尾的删除刚刚已经说了,那么队首的元素什么时候删除呢?由于我们只需要保存i的前k-1个元素中的最大值,所以当队首的元素的索引或下标小于 i-k+1的时候,就说明队首的元素对于求f(i)已经没有意义了,因为它已经不在窗里面了。所以当index[队首元素]<i-k+1时,将队首元素删除。
从上面的介绍当中,我们知道,单调队列与队列唯一的不同就在于它不仅要保存元素的值,而且要保存元素的索引(当然在实际应用中我们可以只需要保存索引,而通过索引间接找到当前索引的值)。
为了让读者更明白一点,我举个简单的例子。
假设数列为:8,7,12,5,16,9,17,2,4,6. N=10,k=3.
那么我们构造一个长度为3的单调递减队列:
首先,那8和它的索引0放入队列中,我们用(8,0)表示,每一步插入元素时队列中的元素如下:
0:插入8,队列为:(8,0)
1:插入7,队列为:(8,0),(7,1)
2:插入12,队列为:(12,2)
3:插入5,队列为:(12,2),(5,3)
4:插入16,队列为:(16,4)
5:插入9,队列为:(16,4),(9,5)
..........依此类推
那么f(i)就是第i步时队列当中的首元素:8,8,12,12,16,16.......
Code
#include <cstdio>
#include<deque>
#include <iostream>
#include <algorithm>
using namespace std; const int MAX_N=1e6+;
int a[MAX_N];
deque<int> p, q; int main()
{
int n, k;
scanf("%d%d", &n, &k);
for(int i = ; i <= n; i++){
scanf("%d", &a[i]);
} for(int i = ; i <= n; i++){
while(!p.empty() && (a[p.back()]>a[i]) ) p.pop_back();
p.push_back(i);
if(i - p.front() == k) p.pop_front();
if(i >= k) printf("%d ", a[p.front()]);
}
printf("\n");
for(int i = ; i <= n; i++) {
while(!q.empty() && (a[q.back()]<a[i]) ) q.pop_back();
q.push_back(i);
if(i - q.front() == k) q.pop_front();
if(i >= k) printf("%d ", a[q.front()]);
}
}
if(i - q.front() == k) q.pop_front();
while(!p.empty() && (p.front()+k<=i) ) p.pop_front();
//在这里的作用一样的,只不过上面的看起来更简洁
附:
deque-双向队列的基本用法
q.front() //返回第一个元素的引用。
q.back() //返回最后一个元素的引用。
q.pop_back() //删除尾部的元素。不返回值。
q.pop_front() //删除头部元素。不返回值。
q.push_back(e) //在队尾添加一个元素e。
q.push_front(e) //在队头添加一个元素e。
[POJ2823] Sliding Window 「单调队列」的更多相关文章
- POJ2823 Sliding Window (单调队列)
POJ2823 Sliding Window Time Limit: 12000MS Memory Limit: 65536K Total Submissions: 38342 Accepte ...
- POJ2823 Sliding Window(单调队列)
题目要输出一个序列各个长度k的连续子序列的最大值最小值. 多次RMQ的算法也是能过的,不过单调队列O(n). 这题,队列存元素值以及元素下标,队尾出队维护单调性然后入队,队首出队保持新元素下标与队首元 ...
- POJ 2823 Sliding Window(单调队列入门题)
Sliding Window Time Limit: 12000MS Memory Limit: 65536K Total Submissions: 67218 Accepted: 190 ...
- 题解报告: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 ...
- poj 2823 Sliding Window(单调队列)
/* 裸地单调队列.. 第一次写 写的好丑.... */ #include<iostream> #include<cstdio> #include<cstring> ...
- 【POJ 2823 Sliding Window】 单调队列
题目大意:给n个数,一个长度为k(k<n)的闭区间从0滑动到n,求滑动中区间的最大值序列和最小值序列. 最大值和最小值是类似的,在此以最大值为例分析. 数据结构要求:能保存最多k个元素,快速取得 ...
- POJ 2823 Sliding Window 【单调队列】
题目链接:http://poj.org/problem?id=2823 题目大意:给出一组数,一个固定大小的窗体在这个数组上滑动,要求出每次滑动该窗体内的最大值和最小值. 这就是典型的单调队列,单调队 ...
- 【POJ 2823】Sliding Window(单调队列/堆)
BUPT2017 wintertraining(16) #5 D POJ - 2823 题意 给定n,k,求滑窗[i,i+k-1]在(1<=i<=n)的最大值最小值. 题解 单调队列或堆. ...
- POJ 2823 Sliding Window(单调队列 || 线段树)题解
题意:求每个长度为k的数组的最大值和最小值 思路: 1.用线段树创建维护最大值和最小值,遍历询问,简单复习了一下...有点手生 2.单调队列: 可以看一下详解 单调队列顾名思义就是一个单调递增或者递减 ...
随机推荐
- SYN5104型 时间综合测试仪
SYN5104型 时间综合测试仪 gps时钟测试仪时间/频率测量仪器使用说明视频链接: http://www.syn029.com/h-pd-73-0_310_6_-1.html 请将此链接复制到浏 ...
- .Net上传文件处理三大范式,及开发注意事项
最近工作内容涉及到一点前端的内容,把学习到的内容记录下来,在今后的开发过程中,不要犯错.本篇只针对一些刚入职的小白及前端开发人员,大牛请绕道!~ 刚开始我们先不讲上传文件的防范问题,先通过一个例子,让 ...
- web页面的时间传入servlet如何转换为可以存入MySQL的Date类型
在web页面中当使用如下语句: <input type="date" name="startTime"/> 提交到servlet中 在servlet ...
- 解决wireshark打开错误
错误提示如下: Lua: Error during loading: [string "/usr/share/wireshark/init.lua"]:44: dofile has ...
- Hive 学习之路(六)—— Hive 视图和索引
一.视图 1.1 简介 Hive 中的视图和RDBMS中视图的概念一致,都是一组数据的逻辑表示,本质上就是一条SELECT语句的结果集.视图是纯粹的逻辑对象,没有关联的存储(Hive 3.0.0引入的 ...
- Spring 之Aop实现日志记录
Aop实现见代码,简单demo实现 package com.idcos.automate.config; import com.idcos.automate.dal.auto.dao.dcos.Dco ...
- 数据库之MySQL的基本使用
数据库简介 数据库 数据库就是一种特殊的文件,其中存储着需要的数据:关系型数据库核心元素: 数据行(记录) 数据列(字段) 数据表(数据行的集合) 数据库(数据表的集合) Ubuntu进入数据库: 1 ...
- wireshark数据包分析实战 第三、四章
1,wireshark支持的协议上千种,开源的. 2,wireshark需要winpcap驱动支持.winpcap驱动的作用通过操作系统捕捉原始数据包.应用过滤器.将网卡切换为混杂模式. 3,捕获文件 ...
- C++ 洛谷 P1731 [NOI1999]生日蛋糕
P1731 [NOI1999]生日蛋糕 一本通上也有. 这TM是一道极其简单的深搜剪枝(DP当然可以的了,这里我只讲深搜). 首先圆柱公式:(有点数学基础都知道) V=πR2H S侧=π2RH S底= ...
- 【POJ - 2386】Lake Counting (dfs+染色)
-->Lake Counting 直接上中文了 Descriptions: 由于近日阴雨连天,约翰的农场中中积水汇聚成一个个不同的池塘,农场可以用 N x M (1 <= N <= ...