单调栈,解决下一个更大元素问题

94 阅读2分钟

单调栈

单调栈不是一种算法,而是一种技巧,本质是:

在遍历数组时,借助一个栈(Stack)来维护一个具有单调性的序列(递增或递减),这样可以在 O(n) 的时间内解决“下一个更大/更小元素”这类问题。

历史背景

  1. 1970–1980 年代,在计算几何、直方图问题等研究里,人们就已经在用类似的“维护单调序列的栈”来解决“下一个更大元素”这类问题。
  2. 1984 年,有一篇关于 直方图最大矩形 (Largest Rectangle in Histogram) 的论文(由 Michael Shamos 等人提出过计算几何中的栈方法),里面其实就隐含了单调栈思想。
  3. 2000 年前后,单调栈作为一种常见的 竞赛算法技巧,开始在 IOI/ACM-ICPC 题解和教材中被系统化。 在中文互联网里,“单调栈”这个名字大概是从 2008–2012 ACM/各类 OJ 题解里逐渐普及开来的(比如 POJ, HDU 上的题解社区)。

常见用法

  • 单调递增栈:栈顶到栈底是递增的 → 常用于找下一个更大元素。
  • 单调递减栈:栈顶到栈底是递减的 → 常用于找下一个更小元素。

典型题目

  • 下一个更大元素(LeetCode 496)
  • 每日温度(LeetCode 739)
  • 柱状图最大矩形(LeetCode 84)
  • 接雨水(LeetCode 42)

示例

[4, 1, 3, 2, 5, 1, 9]找有右面更大的元素。

前置准备:创建一个栈(从上到下保持单调递增,存入的是数组下标),创建一个存放结果的数组result,数组长度和nums相同,初始值都为-1,求解步骤如下:

  1. 遍历下标为0元素:栈为空,将4压入栈中。(目前栈中是4)
  2. 遍历下标为1元素:栈不为空,1小于栈顶元素4,1入栈。(目前栈中是4,1)
  3. 遍历下标为2元素:栈不为空,3大于栈顶元素1,1出栈(栈中存放的是索引,result[1] = nums[2]),3小于栈顶元素4,3入栈。(目前栈中是4,3)
  4. 遍历下标为3元素:栈不为空,2小于栈顶元素3,2入栈。(目前栈中是4,3,2)
  5. 遍历下标为4元素:栈不为空,4大于栈顶元素2,2出栈(result[3] = nums[4]),4大于栈顶元素3,3出栈(result[2] = nums[4]),4入栈。(目前栈中是4)
  6. 遍历下标为5元素:栈不为空,1小于栈顶元素4,1入栈。(目前栈中是4,1)
  7. 遍历下标为6元素:栈不为空,9大于栈顶元素1,1出栈(result[5] = nums[6]),9大于栈顶元素4,4出栈(result[1] = nums[6]),9入栈。(目前栈中是9)