单调栈以及单调队列

单调栈:

  • 定义:

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

  • 作用:单调栈可以找到从左/右遍历第一个比它大/小的元素的位置。时间复杂度为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]);
}
View Code
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;

猜你喜欢

转载自www.cnblogs.com/fonddream/p/9685083.html