[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.单调队列: 可以看一下详解 单调队列顾名思义就是一个单调递增或者递减 ...
随机推荐
- ansible(三)
一.setup模块(收集信息 ) 1.ansible中的setup模块可以收集到的信息 ansible web -m setup ansible_all_ipv4_addresses # ipv4的所 ...
- 一、Linux常用命令
1.ls 作用:列出文件信息,默认为当前目录下 语法: -a:列出所有的文件,包括以.开头的隐藏文件 -d:列出目录本身,并不包含目录中的文件 -h:和-l一起使用,文件大小人类易读 -l:长输出(“ ...
- Spring Boot2(一):使用Spring Boot2集成Mybatis基础搭建
Mybatis 初期使用比较麻烦,需要各种配置文件.实体类.Dao 层映射关联.还有一大推其它配置.mybatis-spring-boot-starter 就是 Spring Boot+ Mybati ...
- Django之forms组件进阶
Django Form表单组件 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要 ...
- .Net之使用Jquery Ajax通过FormData对象异步提交图片文件到服务端保存并返回保存的图片路径
前言: 首先对于图片上传而言,在我们的项目开发中可以说出现的频率是相当的高的.这篇文章中,我将要描述的是在我们.Net中如何使用Jquery Ajax通过FormData对象异步提交图片文件到后台保存 ...
- 开源系统监控工具Nagios、Zabbix和Open-Falcon的功能特性汇总及优缺点比较
Nagios Nagios 全名为(Nagios Ain’t Goona Insist on Saintood),最初项目名字是 NetSaint.它是一款免费的开源 IT 基础设施监控系统,其功能强 ...
- mail.inc实现周密的留言发邮箱
我网站上很多地方都有给我留言的链接,这些链接指向一个地方 http://www.dushangself.site/emlog/?post=8 (源码使用方式:一共四个源代码,第一个和第二个写在一起,, ...
- [apue] 多进程管道读写的一些疑问
对于一对一的pipe: 1) 写进程关闭写管道后,读进程继续读管道会导致read返回0: 2) 读进程关闭读管道后,写进程继续写管道会激发SIGPIPE信号,若捕获,则write返回-1: 而对于多对 ...
- Python编程菜鸟成长记--A1--01--编程语言介绍
目录 1.重点知识 2.什么是编程?为什么要编程? 3.有哪些编程语言? 3.1.机器语言 3.2.汇编语言 3.3.高级语言 3.3.1.编译型语言 3.3.2.解释型语言 3.4.小结 4.主流编 ...
- 蓝桥杯:最大的算式(爆搜 || DP)
http://lx.lanqiao.cn/problem.page?gpid=T294 题意:中文题意. 思路:1.一开始想的是,乘号就相当于隔板,把隔板插入到序列当中,同一个隔板的就是使用加法运算, ...