我们从最简单的问题开始:

给定一个长度为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 「单调队列」的更多相关文章

  1. POJ2823 Sliding Window (单调队列)

    POJ2823 Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 38342   Accepte ...

  2. POJ2823 Sliding Window(单调队列)

    题目要输出一个序列各个长度k的连续子序列的最大值最小值. 多次RMQ的算法也是能过的,不过单调队列O(n). 这题,队列存元素值以及元素下标,队尾出队维护单调性然后入队,队首出队保持新元素下标与队首元 ...

  3. POJ 2823 Sliding Window(单调队列入门题)

      Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 67218   Accepted: 190 ...

  4. 题解报告: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 ...

  5. poj 2823 Sliding Window(单调队列)

    /* 裸地单调队列.. 第一次写 写的好丑.... */ #include<iostream> #include<cstdio> #include<cstring> ...

  6. 【POJ 2823 Sliding Window】 单调队列

    题目大意:给n个数,一个长度为k(k<n)的闭区间从0滑动到n,求滑动中区间的最大值序列和最小值序列. 最大值和最小值是类似的,在此以最大值为例分析. 数据结构要求:能保存最多k个元素,快速取得 ...

  7. POJ 2823 Sliding Window 【单调队列】

    题目链接:http://poj.org/problem?id=2823 题目大意:给出一组数,一个固定大小的窗体在这个数组上滑动,要求出每次滑动该窗体内的最大值和最小值. 这就是典型的单调队列,单调队 ...

  8. 【POJ 2823】Sliding Window(单调队列/堆)

    BUPT2017 wintertraining(16) #5 D POJ - 2823 题意 给定n,k,求滑窗[i,i+k-1]在(1<=i<=n)的最大值最小值. 题解 单调队列或堆. ...

  9. POJ 2823 Sliding Window(单调队列 || 线段树)题解

    题意:求每个长度为k的数组的最大值和最小值 思路: 1.用线段树创建维护最大值和最小值,遍历询问,简单复习了一下...有点手生 2.单调队列: 可以看一下详解 单调队列顾名思义就是一个单调递增或者递减 ...

随机推荐

  1. 高中生也能读懂的Docker入门教程

    Docker 是 Golang 编写的, 自 2013 年推出以来,受到越来越多的开发者的关注.如果你关注最新的技术发展,那么你一定听说过 Docker.不管是云服务还是微服务(Microservic ...

  2. Laravel ---【转】PhpStorm下Laravel代码智能提示

    [转]http://blog.csdn.net/pangchengyong0724/article/details/54706775 第一步:在项目的composer.json中添加如下一行 &quo ...

  3. 浅谈ASP.NET Core中IOC与DI的理解和使用

    说起IOC和DI,使用过ASP.NET Core的人对这两个概念一定不陌生,早前,自己也有尝试过去了解这两个东西,但是一直觉得有点很难去理解,总觉得对其还是模糊不清,所以,趁着今天有空,就去把两个概念 ...

  4. 【转+存】JVM指令集

    jvm指令集: 转载地址:https://www.cnblogs.com/yaoyinglong/p/4300447.html 一.未归类系列A 此系列暂未归类. 指令码    助记符         ...

  5. mac下mysql的卸载和安装

    1. mysql的卸载 1 sudo rm /usr/local/mysql 2 sudo rm -rf /usr/local/mysql* 3 sudo rm -rf /Library/Startu ...

  6. memecached存放session数据

    memcached存放session 1.session数据需要频繁调用. 2.session数据不需要永久性的保存在服务端. 3.在集群中,可以将session存放在memcached中或者是在数据 ...

  7. js深入(三)作用域链与闭包

    在之前我们根绝对象的原型说过了js的原型链,那么同样的js 万物皆对象,函数也同样存在这么一个链式的关系,就是函数的作用域链 作用域链 首先先来回顾一下之前讲到的原型链的寻找机制,就是实例会先从本身开 ...

  8. 真实项目中 ThreadLocal 的妙用

    一.什么是 ThreadLocal ThreadLocal 提供了线程的局部变量,每个线程都可以通过 set() 和 get() 来对这个局部变量进行操作,但不会和其他线程的局部变量冲突,实现了线程间 ...

  9. AD域控制器安装使用

    AD域控制器安装使用 一. 在服务器上安装域控制器 二. 将此服务器提升为域控制器 三. 将主机加入到我们创建的域中 在AD域控制器上查看加入的主机

  10. 二分查找(Binary Search)的递归和非递归

    Binary Search 有时候我们也把它叫做二进制查找 是一种较为高效的再数组中查找目标元素的方法 我们可以通过递归和非递归两种方式来实现它 //非递归 public static int bin ...