单调栈及应用

一、先讲一下什么是单调递增栈,什么是单调递减栈

单调递增栈,从栈底到栈顶依次递增(单调非递减栈:允许有相等)

单调递减栈,从栈底到栈顶依次递减(单调非递增栈:允许有相等)

二、那单调栈的用处是什么?

      求某组数以其中某一个数字为最小值的最大延伸区间 ! 我举一个例子

      当我们有n=6个数例如 2 3 2 5 1 4,从左到右遍历每一个数字,并求出以该数字为最小值,所能延伸的最大区间(即这个区间的数都>=它),比如第一个数2,以它为最小值,所能延伸的最大区间是[{2,3,2,5} ,对于第二个数字3,以它为最小值最大的延伸区间是{3}....以此类推..我们一共可以得到n个这样的区间

      按照传统的作法,我们需要枚举每一个数字,从2 一直到4,然后分别向左右延伸,很容易实现但是复杂度会很高。。当所有的数字都一样,比如 5 5 5 5 5,对于每一个5,我们每次都需要延伸到最左和最右,复杂度是0(n^2);但是如果我们借助单调栈,在我们把这些元素插入栈和弹出栈的过程中就可以巧妙地计算出他们左右延伸的区间范围,

三 模拟单调栈的插入过程

      现在我们有一个栈,是单调递增栈, 对于每一个数字我们用一个结构体包起来struct Node{int num ,in l , int r};//num表示区间的最小值,l表示这个区间的最左边下标,r表示这个区间的最右边下标,于是我们可以先得到 (2,1,1)  (3,2,2) (2,3,3) (5,4,4)(1,5,5) (4,6,6) 进栈和出栈只有两个很简单规则:

当栈中没有元素 或者 栈顶元素的值小于要添加进去的元素的值的时候,直接添加入栈,

当栈中有元素,而且栈顶元素的值大于等于我们要添加进去元素的值,这时候我们需要稍加处理,模拟这个过程(懂了一步):

(2,1,1)入栈,当前栈为空,可以直接入栈: stack [(2,1,1) ]

(3,2,2)入栈,当前栈顶元素值2<3,可以直接入栈 stack : [(2,1,1) (3,2,2)]

(2,3,3)入栈,发现栈顶元素值3>2,这时候(3,2,2)就要弹出去,这时候我们需要从它身上提取两个信息,从(3,2,2)可以看到,3最左可以延伸到下标为2的地方,那么要添加进去的元素(2,3,3)最左l当然也可以延伸到下标2这个地方,所以修改(2,3,3)---->(2,2,3) ; 而栈中(3,2,2)前面的一个元素(2,1,1)可以从(3,2,2,)中知道3最右r可以延伸到下标为2的地方,那么更新(2,1,1)-->(2,1,2)

----------------下面的步骤类似,如果明白了道理可以忽略--------------------------------

(3,2,2)弹出后栈的情况stack[(2,1,2)]  要添加的元素为: (2,2,3)

而弹出来的这个元素 (3,2,2) 就是以3为最小值左右延伸的区间,所以我们可以在插入栈和维护栈的过程得到这些区间

因为我这里是单调递增栈,不允许重复,所以(2,1,2)要弹出,这时候要加入的元素(2,2,3)--->(2,1,3); 而(2,1,2)前面没有元素了,弹出(2,1,2)

此时栈变为stack [(2,1,3)],往后继续添加:

加入(5,4,4)  后 stack [(2,1,3) (5,4,4)]

加入(1,5,5) 后 (1,5,5) --> (1,4,5)   stack---->[(2,1,4) ] 弹出 (5,4,4)      ; 弹出(5,4,4)后 栈顶元素依然较大(2>1)再弹出  stack -->[(1,1,5)]  弹出(2,1,4)

加入(4,6,6) stack -->[(1,1,5) (4,6,6)] ,最后没有要添加的元素了,我们要把栈中剩余的元素弹出, 得到 (4,6,6) ,然后(1,1,5) -->(1,1,6),弹出 (1,1,6)

所以在进栈和出栈的过程中我们得到了6个区间 : (3,2,2) (2,1,2) (5,4,4) (2,1,4) (4,6,6) (1,1,6) 

这里有个不好的地方,对于重复的数字,先出去的范围会比较小,比如(2,1,2),它的正确范围应该是(2,1,4),所以我们可以之间用(2,1,4)不理(2,1,2);

可以看到,每个元素只进栈和出栈一次,所以复杂度在O(n)

----------------------------------------------------------------------------------------------------

四、那么求出这些区间的实际应用:  求最大连续矩形面积 以及 它的变形题 的方法就需要用到这些区间来计算

求最大连续矩阵面积,比如个矩形的高为2 3 2 5 1 4 ,宽都为1 ,如下图:

     

   用上面的方法我们可以得到区间 (3,2,2) (5,4,4) (2,1,4) (4,6,6) (1,1,6)  则最大连续矩阵面积就是 2*(4-1+1) = 8

           

练习题:  poj2080  poj2796

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值