[python 刷题] 84 Largest Rectangle in Histogram
题目:
Given an array of integers
heightsrepresenting the histogram’s bar height where the width of each bar is1, return the area of the largest rectangle in the histogram.
这题也是一个典型的 monotonic stack 的题,解题思路是将 (x, y) 的配对保存到 stack 中,其中 x 为当前 histogram 可能达到的最左侧点,即最大长度,而 y 则是保存当前 histogram 最大高度。其逻辑是,对于 histogram 来说,随着 x 轴增长时,会遇到以下三种情况:
-
y 出现增加

当前情况下,蓝色方块 y 不受限制,x 是可以继续延伸的,此时可以将对应的 x 和 y 存到 stack 中,stack 中的值为
[(0, 50)]:
-
y 出现减少

当前情况下,粉色方块的 y 轴受到限制,x 是不可延续的:

因此就需要进行一个退栈的操作,计算粉色 histogram 的最大面积
-
y 保持不变
这个情况可以单独处理,不过默认作为
y 出现增加情况处理也行
继续过一遍官方提供的案例加深理解:heights = [2,1,5,6,2,3]
当遍历到第一个值时,stack 为空,没有什么可以进行对比的,因此进行一个入栈的操作:

当遍历到第二个值 1 时,stack[-1] 的高度无法延伸到当前值,因此进行一个退栈计算面积、对比最大面积、将新的值压入栈中的操作

注意,这里 🟩 沿用了 🟥 的下标,因为 🟥 的 x 无法延伸到 🟩 ,但是 🟩 的 x 可以反向延伸到 🟥 上:

所以每次出栈的时候都要获取 stack[-1].x 的值,以供让下一个矮一点的 histogram 去继承
遍历到第三个值 5 时,stack[-1] 可以延伸到下一个 histogram 上,因此只是进行一个入栈的操作:
遍历到第四个值 6 时,stack[-1] 可以延伸到下一个 histogram 上,因此只是进行一个入栈的操作:

这两个操作一样,因此合并成一张图
当遍历到 2 的时候,再次遇到 y 轴不可眼神的情况,因此要进行连续退栈的操作,因为 stack 中倒数两个值都比当前遇到的 histogram 要大。其面积的计算方式都为 ( c u r r X − s t a c k [ − 1 ] . x ) × y (currX - stack[-1].x) \times y (currX−stack[−1].x)×y
- 对于
6来说,其面积为 ( 4 − 3 ) × 6 (4 - 3) \times 6 (4−3)×6 - 对于
5来说,其面积为 ( 4 − 2 ) × 5 (4 - 2) \times 5 (4−2)×5 - 对于
1来说,它的 y 轴依然可延续,因此不会进行退栈的操作
此时栈的值如下:

⚠️:上面提到了矮的 histogram 其实是可以反向延长的,因此这里 🟪 占用的是 🟨 的下标
之后重复遍历,一直到完成数组遍历,不过此时 stack 中还是有多余的值的,这个情况下代表 stack 中的 histogram,其 x 轴可以一直延伸到最右端,因此可以用 len(heights) - stack[-1].x 的方法获取其对应的 x,再乘以对应的 y,获得最终面积
代码如下:
class Solution:def largestRectangleArea(self, heights: List[int]) -> int:stack = []max_area = 0for i, h in enumerate(heights):start = iwhile stack and stack[-1][1] > h:prev_i, prev_h = stack.pop()max_area = max(max_area, prev_h * (i - prev_i))start = prev_i# 反向延长 x 轴stack.append((start, h))for i, h in stack:max_area = max(max_area, h * (len(heights) - i))return max_area