Monostack:找邻居助手
Next Greater Element
假设一队人前后站在一起,每个人向前看,由于前面的高个儿挡住了视线,所以只能看到自己和那个歌高个儿之间的同学。问题来了:如何能快速知道每个人前面挡住视线的第一个高个儿呢?于是有了这样的对话:
Bob说:“你看,我们从左往右一个个来看,对于每一个人来说,我们向前看第一个比TA高的就好了。“
Alice说:“那对于每一个人来说,都要比较与前面所有人的身高啊。怎么感觉有更快的方法?如果找到一个高个儿,TA不就是所有之前比TA矮的人的答案了吗?
这种把“之前比TA矮的人“存下来的数据结构就是单调栈。
模版如下[LC 739]:
stack = []
for n in nums:
while stack and n>stack[-1]:
m = stack.pop() # m的nextGreater是n
stack.append(n)
单调栈
单调栈利用了“先入后出“的原则方便我们来寻找nextGreaterElement
或是nextSmallerElement
。有些题要在数组中找对子,单个枚举可能要O(n²),如果要寻找O(n)时间的方法有可能是用单调栈来用空间换时间。

有时候需要把index存下来,来找到nextGreaterElement
的等待时间。
stack = []
for i, n in enumerate(nums):
while stack and n>stack[-1][1]:
j, m = stack.pop() # m等到nextGreater要i-j
stack.append((i, n))
例题:132 模式
给你一个整数数组 nums ,数组中共有 n 个整数。
132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,
并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。
输入:nums = [1,2,3,4]
输出:false
解释:序列中不存在 132 模式的子序列。
我们把数字反转,就变成了寻找231模式。那么从左到右,我们可以用单调递减栈保存2和3。题目只要求寻找是否存在231模式,那么我们利用单调递减栈的性质:所有弹出的数字都比栈中的数字小,把“3“存在栈中,弹出的数字是“2“。我们反向遍历数组,然后看到有比存在的弹出数字更小的“1“,就找到了答案。
下面mmax=stack.pop()
本也可以写作mmax=max(mmax, stack.pop())
。不过由于单调栈的性质:最后弹出的数字相对最大,所以可以略去这个比较。
参考代码:
def find132pattern(nums):
stack = [] # has number "3"
mmax = float('-inf') # number "2"
for n in nums[::-1]: # look for number "1"
if n < mmax: return True
while stack and n > stack[-1]:
mmax = stack.pop()
stack.append(n)
return False
Last updated
Was this helpful?