Skip to content

单调栈

介绍

单调栈:满足单调性的栈结构。

过程:

python
[81, 34, 11, 0]

# insert 14
[81, 34, 14]     # 依次弹出 0 和 11

伪代码:

python
# insert x

while !stk.empty() and stk.top() <= x:
    stk.pop()
# stk.top() 为所求
stk.push(x)

由于单调栈满足单调性,因此栈顶元素始终满足 它是栈中最小/最大的元素

举例:

python
[73, 74, 75, 71, 69, 72, 76, 73], =>

stk = 
[73]           # -1
[73, 74]       # 73
[73, 74, 75]   # 74
[71]           # -1
[69]           # -1
[69, 72]       # 69
[69, 72, 76]   # 72
[69, 72, 73]   # 72

从左到右遍历,按照 比栈顶大压入,比栈顶小弹出 规则。stk.top() 给出的是每个元素 左边第一个比它小的元素,此时单调栈内是单调递增的(栈底到栈顶)。

python
[73, 74, 75, 71, 69, 72, 76, 73], <=

stk = 
[73]               # -1
[76]               # -1
[76, 72]           # 76
[76, 72, 69]       # 72
[76, 72, 71]       # 72
[76, 75]           # 76
[76, 75, 74]       # 75
[76, 75, 74, 73]   # 74

从右往左遍历,按照 比栈顶小压入,比栈顶大弹出 规则。stk.top() 给出的是每个元素 右边第一个比它大的元素,此时单调栈内是单调递减的(栈底到栈顶)。

总结:

  • 从左往右遍历,单调递增:左边第一个比它小的元素
  • 从左往右遍历,单调递减:左边第一个比它大的元素
  • 从右往左遍历,单调递增:右边第一个比它小的元素
  • 从右往左遍历,单调递减:右边第一个比它大的元素

另一种思考方式:元素什么时候被弹出,说明此时找到了它的答案,此时再进行赋值(而不是上面所说的 栈顶即答案)。例如:

python
[73, 74, 75, 71, 69, 72, 76, 73], =>

stk = 
[73]           # -1
[74]           # 73 被 74 弹出,因此 73 右边第一个更大的数是 74
[75]           # 74 被 75 弹出,因此 74 右边第一个更大的数是 75
[75, 71]       # -1
[75, 71, 69]   # -1
[75, 72]       # 69, 71 均被 72 弹出,说明它们右边第一个更大的数均为 72
[76]           # 72, 75 均被 76 弹出,说明它们右边第一个更大的数均为 76
[76, 73]       # -1

ans = 
[74, 75, 76, 72, 72, 76, -1, -1]

伪代码:

python
# insert x

while !stk.empty() and stk.top() < x:
    ans[stk.pop()] = x

stk.push(x)

需要注意的是 这里不取等号

  • 一个是压入栈时就得到答案
  • 一个是弹出栈时才得到答案

模板

查找数组中下一个更大的元素

python
def next_bigger(num: List[int]) -> List[int]:
    n = len(nums)
    stk = []
    
    for i in range(n - 1, -1, -1):
        if len(stk) > 0:

参考

题目

力扣题目:

洛谷题目:

其他题目:

Released under the MIT License.