跳到正文
第 84 题困难

柱状图中最大的矩形

Largest Rectangle in Histogram

在柱状图中找出一块面积最大的矩形,矩形的高度由其中最矮的柱子决定。

在力扣中练习

题目描述

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

 

示例 1:

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:

输入: heights = [2,4]
输出: 4

 

提示:

  • 1 <= heights.length <=105
  • 0 <= heights[i] <= 104

解题思路

主解法

单调栈 · 一次扫描

栈里存高度递增的下标,遇到更矮的柱子就结算栈顶

固定一根柱子作为矩形的高度,它能向左右延伸多远,取决于两边第一个比它矮的柱子。对每根柱子都找左右边界,就是 O(n²)。

单调栈把“找左右第一个更矮”压成一次扫描:栈里保存高度递增的下标。遇到当前柱子比栈顶矮时,栈顶柱子的右边界就是当前下标 i;弹出后新的栈顶就是它的左边界。

分步图解

末尾补一个高度 0 的哨兵,保证所有柱子最终都会弹出;栈内高度保持递增。

柱高 · 当前 best=0
0
1
2
3
4
5
6
7
6
2
5
4
5
1
6
0哨兵
栈里保存递增高度的下标;遇到更矮的柱子时,栈顶矩形无法再向右延伸,立即结算。
本次结算
h=—w=—area=—
下标栈 · 高度递增后进先出
从栈顶进入与离开
    空栈
    栈底
    1 / 4
    遇到更矮的柱子,栈顶矩形立即结算;宽度由弹出后的新栈顶和当前 i 决定。

    宽度是 i - left - 1,面积是 height * width。结算后把当前下标入栈,保持递增。

    分步图解

    i=3 的柱高 4 入栈;栈内高度仍然递增。

    柱高 · 当前 best=6
    0
    1
    2
    3
    4
    5
    6
    7
    6
    2
    5
    4i
    5
    1
    6
    0哨兵
    栈里保存递增高度的下标;遇到更矮的柱子时,栈顶矩形无法再向右延伸,立即结算。
    本次结算
    h=—w=—area=—
    下标栈 · 高度递增后进先出
    3:4↓ 入栈
    1. 1:2高2
    2. 3:4高4← top
    栈底
    1 / 4
    一次连续弹出会得到多个宽度不同的候选,最大面积 12 出现在高度 4 的矩形。

    末尾补一个高度 0 的哨兵,保证所有柱子最终都会弹出,不需要循环结束后再单独清栈。

    自拟柱状图 [6,2,5,4,5,1,6] 在 i=5 时连续弹出 5、4、2,其中高度 4、宽度 3 的矩形面积 12 最大。

    每根柱子最多入栈出栈一次,时间 O(n),空间 O(n)。

    时间 O(n)空间 O(n)

    易错点

    • 忘记哨兵:最后栈里剩余的柱子没有结算。
    • 宽度写成 i - left:多算了一格,应为 i - left - 1。
    • 弹栈后没有更新 left:用的还是旧左边界。
    • 比较用 > 而不是 >=:相等高度时可能少算宽度,但加上哨兵通常仍能得到正确答案;统一用 >= 更稳。
    对照解法

    向两边扩展 · 枚举高度

    以每根柱子为最矮柱,向左右扩展到第一个更矮的位置

    思路最直观,但每个柱子都可能向两边扫完整个数组,最坏 O(n²);仅作对照。

    枚举每根柱子作为矩形的高度 h,向左走到第一个比 h 矮的柱子,向右走到第一个比 h 矮的柱子,中间全部可以纳入矩形。

    面积是 h × (right - left + 1),所有柱子取最大。正确性很直接,但每次扩展都可能扫过大量重复区间。

    在随机数据上它通常比 O(n²) 的最坏情况快,但面试中如果要求线性,必须换成单调栈。

    1. 1枚举每根柱子作为高度。
    2. 2向左扩展到第一个更矮的柱子。
    3. 3向右扩展到第一个更矮的柱子。
    4. 4计算面积并更新最大值。
    时间 O(n²)空间 O(1)

    易错点

    • 扩展条件用 > 而不是 >=:相等高度会把本可包含的柱子排除。
    • 边界下标算错:宽度是 right-left+1。

    代码与演示

    主解法配有图解;对照解法用于比较思路、复杂度或实现方式。

    演示输入heights = [6,2,5,4,5,1,6]

    末尾补一个高度 0 的哨兵,保证所有柱子最终都会弹出;栈内高度保持递增。

    柱高 · 当前 best=0
    0
    1
    2
    3
    4
    5
    6
    7
    6
    2
    5
    4
    5
    1
    6
    0哨兵
    栈里保存递增高度的下标;遇到更矮的柱子时,栈顶矩形无法再向右延伸,立即结算。
    本次结算
    h=—w=—area=—
    下标栈 · 高度递增后进先出
    从栈顶进入与离开
      空栈
      栈底
      1 / 4
      查看 C++ 代码

      延伸阅读

      • 单调栈适合解决“找左右第一个更大/更小元素”的一类问题,柱状图、接雨水、每日温度都用到它。
      • 栈里存下标而不是高度,才能在弹出时计算宽度。