LeetCode 84. 柱状图中最大的矩形
字数 1713 2025-10-27 08:13:40

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

题目描述
给定一个非负整数数组 heights,表示柱状图中每个柱子的高度,每个柱子的宽度为 1。请找出柱状图中能够勾勒出的最大矩形的面积。

例如:
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形是高度为 5 和 6 的柱子组成的区域(第 3 和第 4 根柱子),宽度为 2,面积为 5 × 2 = 10。


解题思路
核心问题是:对于每个柱子,找到它作为矩形高度时能扩展的最大宽度。宽度由左右两侧第一个比它矮的柱子位置决定。

  • 暴力法:对每个柱子,向左/右扫描直到遇到更矮的柱子,计算宽度。时间复杂度 O(n²),会超时。
  • 单调栈优化:通过一次遍历记录每个柱子的左右边界,将时间复杂度降至 O(n)。

步骤详解(单调栈解法)

  1. 问题转化
    对于柱子 i,若以其高度 heights[i] 作为矩形高度,则需找到左右边界:

    • 左边界 left[i]:左侧第一个比 heights[i] 矮的柱子的索引(若没有,则为 -1)。
    • 右边界 right[i]:右侧第一个比 heights[i] 矮的柱子的索引(若没有,则为 n)。
    • 宽度 = right[i] - left[i] - 1,面积 = heights[i] × 宽度
  2. 单调栈的作用

    • 栈内保存柱子的索引,且对应的高度单调递增。
    • 遍历时,若当前柱子高度小于栈顶柱子的高度,则栈顶柱子的右边界确定为当前索引,左边界为栈内下一个索引(若栈空则为 -1)。
    • 通过一次遍历可同时求出所有柱子的左右边界。
  3. 具体步骤

    • 初始化栈 stack,数组 leftright(初始值 -1 和 n)。
    • 遍历索引 i 从 0 到 n-1:
      • 若栈非空且 heights[i] < heights[stack[-1]],则弹出栈顶元素 top,并设置 right[top] = i
      • 设置 left[i] 为栈顶索引(若栈空则为 -1),然后将 i 入栈。
    • 遍历结束后,若栈非空,依次弹出并设置 right[top] = n
    • 计算每个柱子的面积:maxArea = max(maxArea, heights[i] × (right[i] - left[i] - 1))
  4. 示例演示(heights = [2,1,5,6,2,3])

    • 初始:stack = [], left = [-1,-1,-1,-1,-1,-1], right = [6,6,6,6,6,6]
    • i=0:栈空,left[0] = -1,入栈 [0]
    • i=1:高度 1 < 2,弹出 0,right[0] = 1;栈空,left[1] = -1,入栈 [1]
    • i=2:高度 5 > 1,left[2] = 1,入栈 [1,2]
    • i=3:高度 6 > 5,left[3] = 2,入栈 [1,2,3]
    • i=4:高度 2 < 6,弹出 3,right[3] = 4;高度 2 < 5,弹出 2,right[2] = 4;栈顶为 1,高度 1 < 2,left[4] = 1,入栈 [1,4]
    • i=5:高度 3 > 2,left[5] = 4,入栈 [1,4,5]
    • 遍历结束,弹出栈内元素:right[5]=6, right[4]=6, right[1]=6
    • 计算面积:
      • i=0: 2×(1-(-1)-1)=2
      • i=1: 1×(6-(-1)-1)=6
      • i=2: 5×(4-1-1)=10 ← 最大
      • i=3: 6×(4-2-1)=6
      • i=4: 2×(6-1-1)=8
      • i=5: 3×(6-4-1)=3
  5. 复杂度分析

    • 时间复杂度:O(n),每个元素入栈、出栈一次。
    • 空间复杂度:O(n),用于栈和边界数组。

关键点总结

  • 单调栈帮助快速找到每个柱子左右第一个更矮的柱子。
  • 注意遍历结束后栈内剩余元素的右边界处理。
  • 此方法可推广到类似问题(如最大正方形、容器盛水问题)。
LeetCode 84. 柱状图中最大的矩形 题目描述 给定一个非负整数数组 heights ,表示柱状图中每个柱子的高度,每个柱子的宽度为 1。请找出柱状图中能够勾勒出的最大矩形的面积。 例如: 输入: heights = [2,1,5,6,2,3] 输出: 10 解释:最大的矩形是高度为 5 和 6 的柱子组成的区域(第 3 和第 4 根柱子),宽度为 2,面积为 5 × 2 = 10。 解题思路 核心问题是:对于每个柱子,找到它作为矩形高度时能扩展的最大宽度。宽度由左右两侧第一个比它矮的柱子位置决定。 暴力法 :对每个柱子,向左/右扫描直到遇到更矮的柱子,计算宽度。时间复杂度 O(n²),会超时。 单调栈优化 :通过一次遍历记录每个柱子的左右边界,将时间复杂度降至 O(n)。 步骤详解(单调栈解法) 问题转化 对于柱子 i ,若以其高度 heights[i] 作为矩形高度,则需找到左右边界: 左边界 left[i] :左侧第一个比 heights[i] 矮的柱子的索引(若没有,则为 -1)。 右边界 right[i] :右侧第一个比 heights[i] 矮的柱子的索引(若没有,则为 n)。 宽度 = right[i] - left[i] - 1 ,面积 = heights[i] × 宽度 。 单调栈的作用 栈内保存柱子的索引,且对应的高度单调递增。 遍历时,若当前柱子高度小于栈顶柱子的高度,则栈顶柱子的右边界确定为当前索引,左边界为栈内下一个索引(若栈空则为 -1)。 通过一次遍历可同时求出所有柱子的左右边界。 具体步骤 初始化栈 stack ,数组 left 和 right (初始值 -1 和 n)。 遍历索引 i 从 0 到 n-1: 若栈非空且 heights[i] < heights[stack[-1]] ,则弹出栈顶元素 top ,并设置 right[top] = i 。 设置 left[i] 为栈顶索引(若栈空则为 -1),然后将 i 入栈。 遍历结束后,若栈非空,依次弹出并设置 right[top] = n 。 计算每个柱子的面积: maxArea = max(maxArea, heights[i] × (right[i] - left[i] - 1)) 。 示例演示(heights = [ 2,1,5,6,2,3]) 初始: stack = [] , left = [-1,-1,-1,-1,-1,-1] , right = [6,6,6,6,6,6] 。 i=0:栈空, left[0] = -1 ,入栈 [0] 。 i=1:高度 1 < 2,弹出 0, right[0] = 1 ;栈空, left[1] = -1 ,入栈 [1] 。 i=2:高度 5 > 1, left[2] = 1 ,入栈 [1,2] 。 i=3:高度 6 > 5, left[3] = 2 ,入栈 [1,2,3] 。 i=4:高度 2 < 6,弹出 3, right[3] = 4 ;高度 2 < 5,弹出 2, right[2] = 4 ;栈顶为 1,高度 1 < 2, left[4] = 1 ,入栈 [1,4] 。 i=5:高度 3 > 2, left[5] = 4 ,入栈 [1,4,5] 。 遍历结束,弹出栈内元素: right[5]=6 , right[4]=6 , right[1]=6 。 计算面积: i=0: 2×(1-(-1)-1)=2 i=1: 1×(6-(-1)-1)=6 i=2: 5×(4-1-1)=10 ← 最大 i=3: 6×(4-2-1)=6 i=4: 2×(6-1-1)=8 i=5: 3×(6-4-1)=3 复杂度分析 时间复杂度:O(n),每个元素入栈、出栈一次。 空间复杂度:O(n),用于栈和边界数组。 关键点总结 单调栈帮助快速找到每个柱子左右第一个更矮的柱子。 注意遍历结束后栈内剩余元素的右边界处理。 此方法可推广到类似问题(如最大正方形、容器盛水问题)。