单调栈以及单调队列

单调栈:

  • 定义:

栈内的元素,按照某种方式排列下(单调递增或者单调递减),如果新入栈的元素破坏了单调性,就弹出栈内元素,直至满足单调性。

  • 作用:单调栈可以找到从左/右遍历第一个比它大/小的元素的位置。时间复杂度为O(N);

  • 实现方式:(以维护单调递增栈为例)

  进栈操作:每次进入栈时,先检验栈顶元素和进栈元素的大小,如果小于,那么直接入栈;否则,大于等于进栈元素的出栈,直到栈空或者栈顶元素小于入栈元素。

例如:3 8 2 3 1

  • 初始时刻栈为空,3入栈。.....................................栈内元素(3);
  • 8要进栈,8比3大,直接入栈。..............................栈内元素(3,8);
  • 2要进栈,2比8小,全部弹出,2入栈。.................栈内元素(2);
  • 3要进栈,3比2大,直接入栈。..............................栈内元素(2,3);
  • 1要进栈,1比3小,全部弹出,1入栈。.................栈内元素(1);

根据此时求出从左往右第一个比它小的元素。

3   8   2   3   1

0   3   0   2   0

代码:

stack<int>s;
for(int i=1;i<=n;i++)
{
     while(s.size()&&s.top()>=a[i])
     {
           s.pop();
     }
     if(s.empty())
          l[i]=0;
     else
          l[i]=s.top();
     s.push(a[i]);
}

stack<int>s;
for(int i=1;i<=n;i++)
{
     while(s.size()&&s.top()>=a[i])
     {
           s.pop();
     }
     if(s.empty())
          l[i]=0;
     else
          l[i]=s.top();
     s.push(a[i]);
}

例题:poj 2559

题意:给出一个柱形统计图,它的每个项目的宽是1,高度和具体问题有关,现在编辑求出这个柱形图中的最大面积的长方形(n<=le5)

例如:2,1,4,5,1,3,3

面积为8。

分析:

  • 我们首先想到的是逐个考虑每个项目,求出每个项目被包含的长方形。
  • 求出每个被包含的长方形,那么左右两边的高度不能比项目本身的高度低,就是向左右两边延展。
  • 那么用单调栈,时间复杂度是2N:
  1. 求出两边比项目第一个小的位置。为什么不是取两边比项目第一个大的位置呢?因为如果是大的位置,它们之间可能包含比项目本身要小值,就不能达到连续。
  2. 分别对项目进行左右延伸。

单调队列:

  • 定义:

队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。

  • 作用:

对于维护好的单调队列,单调队列是有序的,那么取出最大值(最小值)的复杂度是O(1);

可以拿来优化DP;

  • 操作:

  1. 插入:若新元素从队尾插入后会破坏单调性,则删除队尾元素,直至插入后不再破坏单调性为止,在将其插入单调队列。这和单调栈的插入一样。
  2. 获取最优值:访问首尾元素。
  3. 定长连续子区间的最值问题

例题:

题意:给定一个长度为n的数列,求长度为k的定长连续子区间{a1,a2,a3,a4............,ak-1,ak}...............中每个区间的最大值和最小值。

分析:

  • 当我们看到这个第一个想法应该是枚举起始元素ax,然后再求ax到ak-1+x的最大(小)值,那么区间的复杂度为O(nk);
  • al,al+1,al+2....................ar-1,ar,ar+1,以最大值为例:
  1. 当我们求区间(l,r)最大值时:=max{al,max(al+1,al+2..........ar-1,ar)};
  2. 当我们求区间(l+1,r+1)最大值时:=max{ar+1,max(al+1,al+2..........ar-1,ar)};
  3. 那么再求区间(l+1,r+1)时,我们完全没必要在重新扫描一次。只有当最值在al才需要重新扫描。
  4. 那么如果在区间(l,r)求最大值时,l<i<j<r,如果ai<aj,那么在向右移动的过程中ai就失去了效果,这就与单调队列弹出所不符合单调的元素性质一样。
  5. 当我们将区间从(l,r)移动到(l+1,r+1)时,我们将ar+1插入单调队列中,若队首元素不在(l,r)区间中,那么说明最大值不是(l,r)区间的数,清除队首元素(出队);

例如:4  1  3  2  7  5  6   n=7,k=3;求长度为k的连续子序列的最大值。

  • 初始队列为空,4入队.....................................................队列元素(4);
  • 进队元素为1,1比4小,直接入队...................................队列元素(4,1);
  • 进队元素为3,3比1大,弹出1,3入队...........................队列元素(4,3);那么最大值为4;
  • 进队元素为2,2比3小,直接入队...................................队列元素(4,3,2);因为4不在a2~a4元素中,所有要先弹出4元素,此时最大值为3,队列元素(3,2);
  • 进队元素为7,7比4大,全部弹出...................................队列元素(7);此时最大值为7;
  • 进队元素为5,5比7小,直接入队...................................队列元素(7,5);此时最大值为7;
  • 进队元素为6,6比5大,弹出5,6入队...........................队列元素(7,6);此时最大值为7;

原文地址:https://www.cnblogs.com/fonddream/p/9685083.html

时间: 2024-11-04 19:45:46

单调栈以及单调队列的相关文章

单调栈与单调队列

单调栈 特点 栈内的元素单调递增或者单调递减,可以在\(O(n)\)的时间内求出数列中所有数的左边或右边第一个比其大或小的元素,总时间复杂度为\(O(n)\) 例子 单调栈中一般存索引 一个单调递增栈s = [0, 10, 20 ,t]代表栈中a[1]~a[9]的元素大于a[10]的元素,索引为a[11]~a[19]的元素大于a[20]的元素... 这样我们可以发现在a[10]左边第一个比a[10]的数为a[0],在a[20]左边第一个比a[20]的数为a[10]... 如何实现呢? 每次有元素

单调栈和单调队列

单调栈: 用于解决求出距离当前值最近的满足某个性质的值 1 给定一个长度为N的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出-1. 2 3 输入格式 4 第一行包含整数N,表示数列长度. 5 6 第二行包含N个整数,表示整数数列. 7 8 输出格式 9 共一行,包含N个整数,其中第i个数表示第i个数的左边第一个比它小的数,如果不存在则输出-1. 10 11 数据范围 12 1≤N≤105 13 1≤数列中元素≤109 14 输入样例: 15 5 16 3 4 2 7 5 17 输出样

POJ 2559 Largest Rectangle in a Histogram(单调栈) &amp;&amp; 单调栈

嗯... 题目链接:http://poj.org/problem?id=2559 一.单调栈: 1.性质: 单调栈是一种特殊的栈,特殊之处在于栈内的元素都保持一个单调性,可能为单调递增,也可能为单调递减. 2.模样: 这是一个单调递增的栈,如果我们插入的元素大于栈顶元素,则直接入栈: 如果我们插入的元素小于栈顶,则需要把栈内所有大于它的元素暂时出栈,将这个元素入栈后,再将暂时出栈的元素入栈,维护单调性. 二.模板: 这道题是单调栈的一道模板题: 先思考一个问题,如果题目中的矩形的高度都是单调递增

小结:单调栈 &amp; 单调队列

概要: 对于维护信息具有单调性的性质或者问题可以转化为具有单调性质的模型的题,我们可以考虑用单调栈或单调队列. 技巧及注意: 技巧很多,只要能将问题转化为单调性问题,就好解决了. 当维护固定长度的单调区间,我们考虑用单调队列,如[BZOJ]3314: [Usaco2013 Nov]Crowded Cows(单调队列) 单调栈维护长度时要进行及时更新,例如:[BZOJ]3039: 玉蟾宫(DP/单调栈) 假设完美状态后再进行减法原理,例如:[BZOJ]1628 && 1683: [Usaco

单调栈&amp;单调队列入门

单调队列是什么呢?可以直接从问题开始来展开. Poj 2823 给定一个数列,从左至右输出每个长度为m的数列段内的最小数和最大数. 数列长度:\(N <=10^6 ,m<=N\) 解法① 很直观的一种解法,那就是从数列的开头,将窗放上去,然后找到这最开始的k个数的最大值,然后窗最后移一个单元,继续找到k个数中的最大值. 这种方法每求一个f(i),都要进行k-1次的比较,复杂度为$ O(Nk) $. 显然,如果暴力时间复杂度为 $ O(Nm) $ 不超时就怪了. 解法② 还有一种想法是维护一个B

单调队列&amp;单调栈归纳

单调队列 求长度为M的区间内的最大(小)值 单调队列的基本操作,也就是经典的滑动窗口问题. 求长度为M的区间内最大值和最小值的最大差值 两个单调队列,求出长度为M的区间最大最小值的数组,分别求最大最小值. 求边长为a的正方形内最大值和最小值的最大差值([HAOI2007]理想的正方形) 一个大体的思路是先分别求出以i,j为左上端点的边长为a的矩形中的最大值和最小值.那么该怎么做?,先用单调队列求出一个点右边a个单位的最大值,形成一个新矩阵,再求出新矩阵下边a个单位的最大值.然后最小值再求一边,最

单调队列 单调栈

建议不了解STL的读者先了解几个基本的队列的STL.这也是单调队列和单调栈一般都会用到的. 单调队列:建立一个队列,使队列一直具有单调性(满足单调递增或者单调递减),时间复杂度O(N). 那么我们应该如何做到"使队列一直具有单调性"呢? 以单调递增为例,我们O(N)扫描整个序列,每扫描到一个元素: 1 如果该元素大于等于队列末尾元素,则直接入队; 2 而如果该元素小于已有队列的末尾元素,即不满足单调递增,则使队列中的末尾元素出队,直到该元素符合入队条件,然后入队. 如果只到这里,那么我

7.14 单调栈 单调队列 +dp优化

单调栈和单调队列的定义具体看ppt了 模板: 单调队列 head =1; tail = 0; rep( i ,1 ,n ){ while( head <= tail && a[i] < dq[tail].first)tail--; while( head <= tail && dq[head].second < i-k+1) head++; dq[ ++tail ]={a[i] ,i}; 例题:https://vjudge.net/contest/3

单调栈&amp;单调队列

最近打了三场比赛疯狂碰到单调栈和单调队列的题目,第一,二两场每场各一个单调栈,第三场就碰到单调队列了.于是乎就查各种博客,找单调栈,单调队列的模板题去做,搞着搞着发现其实这两个其实是一回事,只不过利用了容器内元素单调的不同特性,用来加速处理不同的问题. 单调栈解决的是以某个值为最小(最大)值的最大区间,维护的是左右两边第一个比当前位大或者小的数 单调队列解决的是区间最小(最大)值,维护的是区间内的最值 举个栗子,a[i] = { 1,6,3,5,1,2,4 } 如果容器内数字是单调递减的,最后得