单调栈(单调队列的孪生兄弟?)

从题目就可以看出,单调栈和单调队列很相似
首先我们给出简单介绍:

简介

定义:单调栈就是栈内元素单调递增或者单调递减的栈

实际上,如果我们用一些生活情境来说明会更好
(看到的一个很形象的例子)

ZYXZYXZYX约好和zhhe0101一起下馆子,
身为小受,ZYXZYXZYX当然要提前去定桌子啦
但是那个饭店实在是太火了,大清早到了那里就已经排起了长长的队,
于是ZYXZYXZYX取了一张号码牌(当然是来的早的手里的号码牌数字小,但是号不一定是连续的)
ZYXZYXYZYX正打算好好排队的时候,一个妹子突然来找ta,
于是禁不住诱惑的ZYXZYXZYX就跑去和妹子约会了
等到回来的时候,队伍排得更长了
ZYXZYXZYX不能直接插队,不然人家会认为ta是插队的,会把ta胖揍一顿
(ZYXZYXZYX是一个连°Faust、都打不过的蒟,况且ta刚刚丢下了zhhe0101,zhhe0101肯定不会帮他的)
ZYXZYXZYX只能跑到队伍最后,挨个询问排队人手里的号,
ta认为号比他大的人都是“插队”的,于是ZYXZYXZYX就会施魔法把这些人变消失,直到找到号比他小的为止

上面这个很扯很容易引战的例子模拟的就是单调栈的原理

用学术的语言描述一下

给定一个包含若干个整数的数组,
我们从第 1 个元素开始依次加入单调栈里,之后进行更新

单调栈有这样的性质:对于单调递增的栈,如果此时栈顶元素为 b,加入新元素 a 后进行更新时,
如果 a 大于 b,说明 a 在数组里不能再往左扩展了(由于单调栈的单调递增性质,b前面的元素均小于a),
也就是说,如果从 a 在数组中的位置开始往左边遍历,则 a 一定是第一个比 b 大的元素

如果 a 小于 b,说明在数组里,a 前面至少有一个元素不能扩展到 a 的位置
(也就是说,a前面的元素至少有一个大于a),这样整个栈就不单调了
因此我们要找到a应该在的地方(使得在a前面的元素都比a小)

单调栈的维护是 O(n) 级的时间复杂度,因为所有元素只会进入栈一次,并且出栈后再也不会进栈了

性质

  • 单调栈里的元素具有单调性
  • 元素加入栈前,会在栈顶端把破坏栈单调性的元素都删除
  • 使用单调栈可以找到元素向左遍历第一个比他小的元素,也可以找到元素向左遍历第一个比他大的元素。

    第三条性质是最常用的性质,所以我们需要简单解释一下:

    1. 当单调栈中的元素是单调递增的时候,则有:
      (1)当a > b 时,则将元素a插入栈顶,新的栈顶则为a
      (2)当a < b 时,则将从当前栈顶位置向前查找(边查找,栈顶元素边出栈),直到找到第一个比a小的数,停止查找,将元素a插入栈顶(在当前找到的数之后,即此时元素a找到了自己的“位置”)

    2. 当单调栈中的元素是单调递减的时候,则有:
      (1)当a < b 时,则将元素a插入栈顶,新的栈顶则为a
      (2)当a > b 时,则将从当前栈顶位置向前查找(边查找,栈顶元素边出栈),直到找到第一个比a大的数,停止查找,将元素a插入栈顶(在当前找到的数之后,即此时元素a找到了自己的“位置”)

例题

现在我们就来看一道例题:

题目描述:

地上从左到右竖立着 n 块木板,从 1 到 n 依次编号,如下图所示。我们知道每块木板的高度,在第 n 块木板右侧竖立着一块高度无限大的木板,现对每块木板依次做如下的操作:对于第 i 块木板,我们从其右侧开始倒水,直到水的高度等于第 i 块木板的高度,倒入的水会淹没 ai 块木板(如果木板左右两侧水的高度大于等于木板高度即视为木板被淹没),求 n 次操作后,所有 ai 的和是多少。如图,在第 4 块木板右侧倒水,可以淹没第 5 块和第 6 块一共 2 块木板,a4 = 2
这里写图片描述

认真地读过题之后,就可以发现我们可以用单调栈模拟倒水的过程
如果木板从右到左是一个递减序列,显然从哪一格倒水都淹没不了任何一个木板
所以我们可以从右到左把模板的高度扔进一个单调栈中(单调递减)
如果违背了单调递减的规则,我们就进行出栈操作
出栈元素就是能够淹没的木板数量

为了讲的明白一点,我们可以简单模拟一下:

  • INF(最右端的木板入栈)
  • 6入栈
  • 5入栈
  • 4入栈:
    a[4] > a[5],5出栈,cnt++
    a[4] > a[6],6出栈,cnt++
    a[4] < INF,因此ans[4]=cnt=2

(感觉网上的题解都写的超啰嗦。。。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值