http://www.cnblogs.com/whywhy/p/5066306.html

队列和栈是很常见的应用,大部分算法中都能见到他们的影子。

  而单纯的队列和栈经常不能满足需求,所以需要一些很神奇的队列和栈的扩展。

  其中最出名的应该是优先队列吧我觉得,然后还有两种比较小众的扩展就是单调队列和单调栈。

  先来看一个问题,给一个长度为N的数列,a1,a2。。。aN,然后给一个k<=N,求输出b1,b2。。。bN这N个数,其中 bi=max( aj | j<=i && j>i-k && j>0 )。

  比较朴素的想法是用一个Nk复杂度的循环来求,但是这样的话如果N很大的话就太慢了。

  然后还有一种想法是维护一个BST,然后for循环从左到右,依次加入到BST里面,如果某个数超出了k的范围,就从BST中删除。

  伪代码如下:

 void getans() {
BST tree; for(int i=,j=;i<=N;++i) {
tree.insert(a[i]);
while(j<=i-k) {
tree.erase(a[j]);
--j;//应为++j
}
cout<<tree.max()<<endl;
}
}

这样的话因为每个数只insert一次,最多erase一次,所以复杂度是NlogN的,已经很不错了。

  但是BST比较高级,所以速度并不快,那么能不能根据这个问题的特点来设计一种更快的数据结构来解决?

  先看这个问题,如果for循环从左到右来求b的话,就像是有个长度为k的框框一次次向右移动,每次求框内的最大值。

  

  如果类比到队列的话,就是for循环的时候每次push一个数在队尾,然后把最前面那个超出的数pop出来,然后求队列内的最大值就行了。

  但是一般的队列并不能求最大值,就需要一些扩展型的队列了。

  单调队列就是队列内所有数都是单调递增的或者递减的。下面按照从队首到队尾递减的队列来讨论。

  先看看push(x):

    如果当前队列为空的话,直接push进去就行。

    如果当前队列末尾的数比x大,那么直接放到队尾,这时仍然是单调的。

    如果末尾的数比x小的话,就扔掉队尾的数,然后再重复上面的步骤push(x)。

    比如队列中是  5 4 2 1,然后push 3 进去的话,就把1和2扔掉,变成5 4 3,如果再push 7 进去的话,就把5 4 3 扔掉,队列变成了 7 。

  然后pop的话和一般队列没有区别。

  然后这个数据结构如果应用到这个问题上的话,看看答案是否是对的。

  for循环从左到右,然后每次push当前的ai,然后判断如果队首的元素的位置超出了框框,就pop出来扔掉。然后这是bi就等于pop完之后队首的数。

 struct Queue {
int val[MaxN],pos[MaxN];
int first,last; void init() {
first=last=;
} void push(int v,int p) {
while(last-first> && val[last-]<=v) --last;
val[last]=v;
pos[last++]=p;
} void pop() {
if(last-first>) ++first;
} int firstPos() {
return pos[first];
} int firstVal() {
return val[first];
}
}; void getans() {
Queue que;
que.init(); for(int i=;i<=N;++i) {
que.push(a[i],i);
while(que.firstPos()<=i-k) que.pop();
cout<<que.firstVal().val<<endl;
}
}

  先来看看这样对不对,首先队列是单调的,所以队首的数一定是最大的,这个数在失效的时候,在他位置前面的所有数也一定都失效了,而他位置后面的所有数还没失效,仍然符合最大的前面,也就是最大的仍然还在队列中没有被扔掉。所以下一次询问的时候仍然答案是对的。

  然后看看复杂度如何,每个数只push了一次,然后最多会被扔掉一次,所以虽然push里面有while循环,但是这N个数每个最多被遍历一次然后就被扔掉了,所以for循环N次下来,均摊的复杂度是O(1)的对于每个push和pop操作,所以总复杂度是O(N)的。

  然后这就是单调栈,单调栈和单调队列区别不大,都是每次push的时候要维护单调性。

  有一道题目 POJ 2796 ,需要先进行转化然后在使用单调栈来解决。

  单调栈和单调队列在大部分情况下是一种工具,对于一些问题能够优化到N的复杂度,这样会比logN快很多。所以其实有些情况下不用这个,用其他的数据结构也是可以做的。

数据结构录 之 单调队列&单调栈。(转)的更多相关文章

  1. 单调队列 && 单调栈

    单调队列 && 单调栈 单调队列 维护某个滑动区间的min or max,可用于dp的优化 以维护min为例,采用STL双端队列实现 每次加入元素x前 先检查队首元素==滑动后要删除的 ...

  2. 联赛模拟测试18 A. 施工 单调队列(栈)优化DP

    题目描述 分析 对于 \(Subtask\ 1\),可以写一个 \(n^3\) 的 \(DP\),\(f[i][j]\) 代表第 \(i\) 个建筑高度为 \(j\) 时的最小花费,随便转移即可 时间 ...

  3. 数据结构录 之 单调队列&单调栈。

    队列和栈是很常见的应用,大部分算法中都能见到他们的影子. 而单纯的队列和栈经常不能满足需求,所以需要一些很神奇的队列和栈的扩展. 其中最出名的应该是优先队列吧我觉得,然后还有两种比较小众的扩展就是单调 ...

  4. 【NOIP数据结构专项】单调队列单调栈

    [FZYZ P1280 ][NOIP福建夏令营]矩形覆盖 Description 有N个矩形,矩形的底边边长为1,且均在X轴上,高度给出,第i个矩形的高为h[i],求最少需要几个矩形才能覆盖这个图形. ...

  5. 单调队列&单调栈

    单调队列 例题: Poj 2823给定一个数列,从左至右输出每个长度为m的数列段内的最小数和最大数.数列长度:N<=106,m<=N 对于单调队列,我们这样子来定义: 1.维护区间最值 2 ...

  6. 小Z爱序列(NOIP信(sang)心(bin)赛)From FallDream(粗制单调队列&单调栈的算法解析)

    原题: 小Z最擅长解决序列问题啦,什么最长公共上升然后下降然后上升的子序列,小Z都是轻松解决的呢. 但是小Z不擅长出序列问题啊,所以它给了你一道签到题. 给定一个n个数的序列ai,你要求出满足下述条件 ...

  7. 大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 9851  Solved: 4318[Submi ...

  8. POJ 3494 Largest Submatrix of All 1’s 单调队列||单调栈

    POJ 3494 Largest Submatrix of All 1’s Description Given a m-by-n (0,1)-matrix, of all its submatrice ...

  9. 单调队列&单调栈归纳

    单调队列 求长度为M的区间内的最大(小)值 单调队列的基本操作,也就是经典的滑动窗口问题. 求长度为M的区间内最大值和最小值的最大差值 两个单调队列,求出长度为M的区间最大最小值的数组,分别求最大最小 ...

随机推荐

  1. 批处理 ECHO命令输出空行

    众所周知,如果echo后面跟一个环境变量,但是该变量却为空时,相当于不加任何参数的echo,即输出当前echo是on还是off.很多文章或者教程给出的解决方案都是在echo后面加一个点号echo.,这 ...

  2. Vue页面上实时显示当前时间,每秒更新

    有时候我们需要在页面上添加一个类似时钟的东西来实时显示当前时间,这个时候我们可以利用定时器来完成这个功能 <div id="app"> {{date}} </di ...

  3. python获取当前目录路径和上级路径

    在使用python的时候总会遇到路径切换的使用情况,如想从文件夹test下的test.py调用data文件夹下的data.txt文件: . └── folder ├── data │ └── data ...

  4. shutil 模块 高级的文件、文件夹、压缩包 处理模块

    高级的文件.文件夹.压缩包 处理模块 # 将文件内容拷贝到另一个文件中 shutil.copyfileobj(fsrc, fdst[, length]) import shutil shutil.co ...

  5. Chrome 正在受到自动化软件控制 – 解决办法

    1.在这个文件下修改一行代码就可以了,文件路径E:\Miniconda3\envs\env3\Lib\site-packages\selenium\webdriver\chrome\options.p ...

  6. ERROR 1396 (HY000): Operation CREATE USER failed for 'root'@'localhost'

    安装ranger时MySQL报错,查看MySQL数据库,发现host=localhost这一列被删除了,插入这一列就好了,具体操作如下: 解决办法: 进入MySQL数据库 use mysql: &qu ...

  7. [Idea]安装avtiviti插件以及 插件中文乱码

    安装插件 打开IDEA,按ctrl+alt+S,打开Pluging 乱码问题 idea 安转activiti插件后,编辑流程图发现保存后中文乱码,并且idea的字符集(Settings—>Edi ...

  8. 0402-服务注册与发现-Eureka Server使用、将服务注册到Eureka server上

    一.Eureka Server使用 官方文档地址:http://cloud.spring.io/spring-cloud-static/Edgware.SR3/single/spring-cloud. ...

  9. Python基础-configparser和hashlib模块

    configparser模块 import configparser config = configparser.ConfigParser() #将配置写入到文件 config[', 'Compres ...

  10. zabbix-2.4.8-1添加MySQL主从状态监控

    1.安装zabbix-agentyum -y install zabbix-2.4.8-1.el6.x86_64.rpm zabbix-agent-2.4.8-1.el6.x86_64.rpm 安装以 ...