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

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

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

  先来看一个问题,给一个长度为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中删除。

  伪代码如下:

 1 void getans() {
 2     BST tree;
 3
 4     for(int i=1,j=1;i<=N;++i) {
 5         tree.insert(a[i]);
 6         while(j<=i-k) {
 7             tree.erase(a[j]);
 8             --j;
 9         }
10         cout<<tree.max()<<endl;
11     }
12 }

  这样的话因为每个数只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完之后队首的数。

 1 struct Queue {
 2     int val[MaxN],pos[MaxN];
 3     int first,last;
 4
 5     void init() {
 6         first=last=0;
 7     }
 8
 9     void push(int v,int p) {
10         while(last-first>0 && val[last-1]<=v) --last;
11         val[last]=v;
12         pos[last++]=p;
13     }
14
15     void pop() {
16         if(last-first>0) ++first;
17     }
18
19     int firstPos() {
20         return pos[first];
21     }
22
23     int firstVal() {
24         return val[first];
25     }
26 };
27
28 void getans() {
29     Queue que;
30     que.init();
31
32     for(int i=1;i<=N;++i) {
33         que.push(a[i],i);
34         while(que.firstPos()<=i-k) que.pop();
35         cout<<que.firstVal().val<<endl;
36     }
37 }

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

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

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

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

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

转载于:https://www.cnblogs.com/whywhy/p/5066306.html

数据结构录 之 单调队列单调栈。相关推荐

  1. POJ - 3250 Bad Hair Day(单调队列/单调栈)

    题目链接:点击查看 题目大意:给出n只牛,高度参差不齐,所有的牛都朝向右边,他们可以看到右边所有没有遮挡并且比自己低的牛,问每只牛可以看到的牛的数量总和是多少 题目分析:这个题目让求每只牛看到的牛的数 ...

  2. 入门经典_Chap08_题解总结:极角扫描法 滑动窗口 单调队列 单调栈

    总结  本章主要关注一个重要的问题 – 单调队列和单调栈的使用  同时还有一些其他的问题,如扫描法,递归的思想, 构造, 分治, 二分等 知识点 单调队列 和 单调栈 题目 UVA - 1606 Am ...

  3. 数据结构与算法 | 用队列实现栈

    上一章实现了用栈来实现队列,这一次我们试试用队列来实现栈. 因为栈的特性是先进后出,队列是先进先出. 所以我们可以想到用两个队列,一个空队列,一个放数据,当我们入队的时候将数据直接放入非空队列,出队的 ...

  4. 数据结构:线性数据结构(2)-队列(栈,队列,deques, 列表)

    队列:FIFO 1.队列的抽象数据类型 队列抽象数据类型由以下结构和操作定义.如上所述,队列被构造为在队尾添加项的有序集合,并且从队首移除.队列保持 FIFO 排序属性.队列操作如下: Queue() ...

  5. Go语言学习笔记【11】 数据结构之稀疏矩阵、队列、栈

    [声明] 非完全原创,部分内容来自于学习其他人的理论和B站视频.如果有侵权,请联系我,可以立即删除掉. 一.稀疏矩阵 若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵 ...

  6. 【数据结构】单调栈和单调队列 详解+例题剖析

    算法:单调栈和单调队列 一.单调栈和单调队列 二.单调栈例题 1.模板题入门 2.不懂不要急,看这道题 三.单调队列例题 1.入门 2.进阶 一.单调栈和单调队列 单调栈和单调队列与普通的栈,队列不同 ...

  7. 算法学习12: 单调队列和单调栈

    算法学习12: 单调队列和单调栈 单调队列 单调队列解决的问题: 窗口内最大/最小值的更新结构 单调队列的结构和操作 单调队列的应用 题目一: 生成窗口最大值数组[leetcode 239](http ...

  8. 【C++】单调队列 详解

    今天我们来讲一下单调队列与栈. 这两种数据结构虽然没有在c++的stl中有直接的实现,但是在做题过程中,很容易有单调队列(栈)的使用,尤其是在一些比较难的题目中. 目录 单调队列 1.1 单调队列介绍 ...

  9. tyvj1305 最大子序和 【单调队列优化dp】

    描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7 当m=2或m=3时,S=5+1=6 输 ...

最新文章

  1. TensorFlow 相关 URL
  2. 使用SAP ABAP BSP应用实现一个环状的进度条
  3. leetcode 49. 字母异位词分组(排序+hash)
  4. 判断点是否在给定四边形内的算法
  5. C# A potentially dangerous 问题解决
  6. C Primer Plus (Stephen Prata 著)
  7. python文件都是脚本吗_.py文件是python脚本吗
  8. cas5.2集成ldap
  9. matlab神经网络预测模型,matlab人工神经网络预测
  10. runtime Method
  11. ireport 实现动态合并单元格
  12. 第一章 公共政策学的学科要素
  13. 梦想遥不可及,现实寸步不离
  14. android 新浪微博平台开发之 ——授权登录
  15. 【3D游戏建模全流程教学】在Maya中制作小岛模型
  16. Android应用分身的实现和解析
  17. 汇编语言 ORG伪指令
  18. [考试反思]0820NOIP模拟测试27:幻影
  19. CSS 文字内容底部对齐
  20. 电影主题网站设计——仿360影视网站(1页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设

热门文章

  1. 【☘️C语言の单链表是否有环问题☘️】
  2. Linux chmod命令小贴士
  3. OpenFeign组件的使用(使用nacos作为服务注册中心)
  4. java自定义注解解析及自定义注解
  5. STM32开发 -- WIFI那些事儿(一)
  6. Android 插件化原理解析——Service的插件化
  7. JZOJ 1598. 文件修复
  8. mysql新手注意事项_学习mysql的注意事项!
  9. iphone看python文件_Python实战 | 只需 ”三步“ 爬取二手iphone手机信息(转发送源码)...
  10. 你认识的python有你想的那么神吗_Python的10个神奇的技巧