zhangdizhangdi

84. 柱状图中最大的矩形 🟥

题目

leetcode 困难

题目

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。

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

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

题解

解题思路

我们需要维护一个高度单调递增的栈(栈里存的是柱子的索引):

  • 走上坡路(入栈):如果当前柱子比栈顶的柱子高,说明栈顶的柱子还能继续向右延伸,咱们先别急着算它的面积,把它(的索引)乖乖压入栈中。
  • 走下坡路(出栈并计算):如果遇到一个柱子比栈顶的矮,好戏上演了!
    • 这说明栈顶柱子的“右边界”找到了!(就是当前这个矮柱子)。
    • 那它的“左边界”是谁呢?因为栈是单调递增的,所以栈顶下面压着的那个元素,就是它左边第一个比它矮的柱子!
    • 左右边界都有了,立刻把栈顶弹出,计算它的面积。
    • 一直弹出,直到当前柱子不再比栈顶矮,再把它入栈。
复杂度
  • 时间复杂度:O(N)
  • 空间复杂度:O(N)
js
function largestRectangleArea(heights) {
  let maxArea = 0
  // 技巧:在数组首尾各加一个 0 作为“哨兵”
  // 首部 0:防止栈空,提供绝对的左边界
  // 尾部 0:强行让所有仍在栈里的元素出栈并结算
  const newHeights = [0, ...heights, 0]

  // 栈里存放的是索引
  const stack = []

  for (let i = 0; i < newHeights.length; i++) {
    console.log('♻️ i', i, '【', newHeights[i], '】')
    console.log(
      'stack',
      stack.map(idx => `${idx}${newHeights[idx]}】`).toString(),
    )

    // 如果遇到了“矮子”(当前高度 < 栈顶高度),说明栈顶柱子的右边界确定了
    while (
      stack.length > 0 &&
      newHeights[i] < newHeights[stack[stack.length - 1]]
    ) {
      // 1. 被结算的柱子出栈,它是我们要计算的高
      const hIdx = stack.pop()
      const h = newHeights[hIdx]

      console.log('出栈柱子', hIdx, '【', h, '】')

      // 2. 此时的新栈顶,就是被弹出柱子的“左边界”
      const leftIdx = stack[stack.length - 1]

      // 3. 当前柱子 i,就是被弹出柱子的“右边界”
      // 宽度 = 右边界 - 左边界 - 1
      const w = i - leftIdx - 1

      console.log('左边界', leftIdx, '【', newHeights[leftIdx], '】')

      // 4. 计算面积并挑战最大值
      maxArea = Math.max(maxArea, h * w)
    }

    console.log('maxArea', maxArea)

    // 走上坡路或平路,直接入栈等待未来的右边界
    stack.push(i)

    console.log(
      'stack',
      stack.map(idx => `${idx}${newHeights[idx]}】`).toString(),
    )
  }

  return maxArea
}

console.log('🌰', largestRectangleArea([2, 1, 5, 6, 2, 3]))
console.log('----------------')
console.log('🌰', largestRectangleArea([2, 4]))
执行结果
♻️ i 00
stack 
maxArea 0
stack 00
♻️ i 12
stack 00
maxArea 0
stack 00】,12
♻️ i 21
stack 00】,12
出栈柱子 12
左边界 00
maxArea 2
stack 00】,21
♻️ i 35
stack 00】,21
maxArea 2
stack 00】,21】,35
♻️ i 46
stack 00】,21】,35
maxArea 2
stack 00】,21】,35】,46
♻️ i 52
stack 00】,21】,35】,46
出栈柱子 46
左边界 35
出栈柱子 35
左边界 21
maxArea 10
stack 00】,21】,52
♻️ i 63
stack 00】,21】,52
maxArea 10
stack 00】,21】,52】,63
♻️ i 70
stack 00】,21】,52】,63
出栈柱子 63
左边界 52
出栈柱子 52
左边界 21
出栈柱子 21
左边界 00
maxArea 10
stack 00】,70
🌰 10
----------------
♻️ i 00
stack 
maxArea 0
stack 00
♻️ i 12
stack 00
maxArea 0
stack 00】,12
♻️ i 24
stack 00】,12
maxArea 0
stack 00】,12】,24
♻️ i 30
stack 00】,12】,24
出栈柱子 24
左边界 12
出栈柱子 12
左边界 00
maxArea 4
stack 00】,30
🌰 4