《单调栈和单调队列(精品) .ppt》由会员分享,可在线阅读,更多相关《单调栈和单调队列(精品) .ppt(12页珍藏版)》请在三一办公上搜索。
1、,单调栈和单调队列,by Tisuama,定义:,单调栈:栈内的元素,按照某种方式排序下(单调递增或者单调递减)如果新入栈的元素破坏了单调性,就弹出栈内元素,直到满足单调性,为什么要学习单调栈:,它可以很方便地求出某个数的左边或者右边第一个比它大或者小的元素,而且总时间复杂度O(N)。,如何维护单调栈:(以维护单调递增栈为例),进栈操作:每次入栈前先检验栈顶元素和进栈元素(x)的大小,如果小于x,就让x直接入栈。如果栈顶元素大于等于x,那么出栈,直到栈空或者栈顶元素小于x,例如:1 4 3 6 0,初始时刻栈空,1入栈。-栈内元素(1),4要进栈,4大于1,所以直接进栈.-栈内元素(1,4),
2、3要进栈,3小于4,4出栈,3进栈.-栈内元素(1 3),6要进栈,6大于3,6直接进栈。-栈内元素(1,3,6),0要入栈,1,3,6都出栈,-栈内元素(0),例题,POJ 2559,题意:给出一个柱形统计图(histogram),它的每个项目的宽度是1,高度和具体问题有关。现在编程求出在这个柱形图中的最大面积的长方形(n=1e5),例如:2,1,4,5,1,3,3,最大面积:8,那么问题来了:如何算?,分析,逐个考虑每个项目,那么如何得到每个项目被包含的长方形了?,假设考虑到项目x,通过简单的思考,我们可以得出结论,x的左右两边的项目高度都不能比x低,那么如何求项目x的两边延伸长度?,我们
3、想到了单调栈?为什么(以求x左边延伸长度为例),假设我们建立一个单调递增栈,那么我们可以轻松地求得x左边比x小的第一个数的位置。,那么问题来了:为什么是单调递增栈,为什么是比x小?,求x右边延伸相同处理,实现方式,栈(以求x的向左延伸为例),int top=0,smaxn;for(int i=1;i=n;i+),while(top,Li=(top=0?1:stop+1);,s+top=i;,并查集,L1=1;for(inti=2;i=n;i+),int pos=i;while(pos-1=1,Li=pos;,定义:,单调队列:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,
4、只有队尾可以进行入队操作。,为什么要学习单调队列:,对于维护好的单调队列,对内元素是有序的,那么取出最大值(最小值)的复杂度是O(1),可以拿来优化DP(然而弱不会),如何维护单调队列:,队尾入队的时候维护单调性。,例题,POJ 2823,给定一个大小已知的数组以及一个大小已知的滑动窗口,窗口每个时刻向后移动一位,求出每个时刻窗口中数字的最大值和最小值。(n=1e6),例如:input8 31 3-1-3 5 3 6 7,output:-1-3-3-3 3 33 3 5 5 6 7,如何解啊如何解?,区间最值问题:我们想到了啥?线段树?RMQ?,新姿势!单调队列!O(n)!,O(nlog(n)
5、!,分析,以得到最小值为例:,我们维护一个单增的队列,那么每次滑动窗口入队之后就要得到一个区间最小值,按照刚才的理论,直接取队首元素就可以了?,具体做法:每次滑动窗口要得到最小值的时候,判断队首元素是否过期,如果过期,就从队首出队,继续找。,最大值做法同上:维护一个单减队列。,实现方式,void get_min()int tail=0,head=1;for(int i=1;i=ai)-tail;q+tail=ai;ptail=i;for(int i=k;i=ai)-tail;q+tail=ai;ptail=i;while(pheadi-k+1)+head;mii-k+1=qhead;,Special,head,tail,我们发现,每次从尾部入队前都会比较大小-注意对象是队内元素,但是队内元素都是按次序入队,即队内元素都是比当前要入队的次序小,所以单调队列里的元素都是有次序的(由小到大)所以,我们要查找某个id的时候,也可以二分。,最后练习的六道题目已经在VJ上挂出来了,欢迎AC,谢谢观赏,
链接地址:https://www.31ppt.com/p-2657646.html