线性表--单调栈
Posted Abro.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性表--单调栈相关的知识,希望对你有一定的参考价值。
目录
前言
栈的存储结构分为顺序存储结构和链式存储结构,并且为了解决部分需求,引入单调栈的概念。
一、单调栈简介
单调栈(Monotone Stack):一种特殊的栈。在栈的「先进后出」规则基础上,要求从 栈顶 到 栈底 的元素是单调递增(或者单调递减)。其中满足从栈顶到栈底的元素是单调递增的栈,叫做单调递增栈。满足从栈顶到栈底的元素是单调递减的栈,叫做单调递减栈。
注意:这里定义的顺序是从「栈顶」到「栈底」,其它文章若是从栈底到栈顶,则要具体情况具体分析,本文是从栈顶到栈底。
1.1 单调递增栈
只有比栈顶元素小的元素才能直接进栈,否则需要先将栈中比当前元素小的元素出栈,再将当前元素入栈。
这样就保证了:栈中保留的都是比当前入栈元素大的值,并且从栈顶到栈底的元素值是单调递增的。
单调递增栈的入栈、出栈过程如下:
- 假设当前进栈元素为
x
,如果栈顶元素大于x
,则直接入栈。 - 否则从栈顶开始遍历栈中元素,把小于
x
或者等于x
的元素弹出栈,直到遇到一个大于x
的元素为止,然后再把x
压入栈中。
1.2 单调递减栈
只有比栈顶元素大的元素才能直接进栈,否则需要先将栈中比当前元素大的元素出栈,再将当前元素入栈。
这样就保证了:栈中保留的都是比当前入栈元素小的值,并且从栈顶到栈底的元素值是单调递减的。
单调栈减栈的入栈、出栈过程如下:
- 假设当前进栈元素为
x
,如果栈顶元素大于x
,则直接入栈。 - 否则从栈顶开始遍历栈中元素,把大于
x
或者等于x
的元素弹出栈,直到遇到一个小于x
的元素为止,然后再把x
压入栈中。
二、单调栈适用场景
单调栈可以在时间复杂度为O(n)的情况下,求解出某个元素左边或者右边第一个比它大或者小的元素。
所以单调栈一般用于解决以下几种问题:
- 寻找左侧第一个比当前元素大的元素
- 寻找左侧第一个比当前元素小的元素
- 寻找右侧第一个比当前元素大的元素
- 寻找右侧第一个比当前元素小的元素
2.1 寻找左侧第一个比当前元素大的元素
- 从左到右遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素左侧第一个比它大的元素就是将其「插入单调递增栈」时的栈顶元素。如果插入时的栈为空,则说明左侧不存在比当前元素大的元素。
2.2 寻找左侧第一个比当前元素小的元素
- 从左到右遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素左侧第一个比它小的元素就是将其「插入单调递减栈」时的栈顶元素。如果插入时的栈为空,则说明左侧不存在比当前元素小的元素。
2.3 寻找右侧第一个比当前元素大的元素
- 从左到右遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素右侧第一个比它大的元素就是将其「弹出单调递增栈」时即将插入的元素。如果该元素没有被弹出栈,则说明右侧不存在比当前元素大的元素。
- 从右到左遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素右侧第一个比它大的元素就是将其「插入单调递增栈」时的栈顶元素。如果插入时的栈为空,则说明右侧不存在比当前元素大的元素。
2.4 寻找右侧第一个比当前元素小的元素
- 从左到右遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素右侧第一个比它小的元素就是将其「弹出单调递减栈」时即将插入的元素。如果该元素没有被弹出栈,则说明右侧不存在比当前元素小的元素。
- 从右到左遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素右侧第一个比它小的元素就是将其「插入单调递减栈」时的栈顶元素。如果插入时的栈为空,则说明右侧不存在比当前元素小的元素。
三、单调栈模板
以从左到右遍历元素为例,介绍一下构造单调递增栈和单调递减栈的模板。
3.1 单调递增栈模板(python代码)
def monotoneIncreasingStack(nums):
stack = []
for num in nums:
while stack and num >= stack[-1]:
stack.pop()
stack.append(num)
3.2 单调递减栈模板(python代码)
def monotoneDecreasingStack(nums):
stack = []
for num in nums:
while stack and num <= stack[-1]:
stack.pop()
stack.append(num)
总结
可以应用单调栈来刷一下力扣的几道题!
以上是关于线性表--单调栈的主要内容,如果未能解决你的问题,请参考以下文章