1.题目描述
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
2.解题思路
思路:
首先,要想找到第 i 位置最大面积是什么?
是以i 为中心,向左找第一个小于 heights[i] 的位置 left_i;向右找第一个小于于 heights[i] 的位置 right_i,即最大面积为 heights[i] * (right_i - left_i -1),如下图所示:
所以,我们的问题就变成如何找 right_i 和 left_i?
利用单调栈,我们需要一个递增栈,当遇到大的数字直接进栈,而当遇到小于栈顶元素的数字时,就要取出栈顶元素进行处理了(栈顶元素相当于heights[i]),于是乎遇到的较小的数字只是一个触发,表示现在需要开始计算矩形面积了,为了使得最后一块板子也被处理,这里用了个小 trick,在高度数组最后面加上一个0,这样原先的最后一个板子也可以被处理了。由于栈顶元素是矩形的高度,那么关键就是求出来宽度,单调栈中不能放高度,而是需要放坐标。由于我们先取出栈中最高的板子,那么就可以先算出长度为1的矩形面积了,然后再取下一个板子,此时根据矮板子的高度算长度为2的矩形面积,以此类推,直到数字大于栈顶元素为止,再次进栈,巧妙的一比!宽度 (i-stack[-1]-1) ,其中i相当于上图的 right_i(向右找第一个小于于 heights[i] 的位置 right_i),其中stack[-1]相当于上图的 left_i (向左找第一个小于 heights[i] 的位置 left_i)
在首尾加了两个0,这个设计真的很精妙啊,我开始用栈这个方法去解决问题的时候,就在考虑如果遍历之后,栈不为空,那么还需要一步:即弹出栈中所有元素,分别计算最大面积。然而当加了两个0以后,在结束后,栈一定为空!
首部加0是因为在计算宽度(i-stack[-1]-1)时需要stack[-1]
参考:https://www.cnblogs.com/grandyang/p/4322653.html
3.代码实现
class Solution(object):
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
heights = [0] + heights + [0]
size = len(heights)
stack = []
res = 0
i = 0
while i < size:
# 加入=是因为前后都插入了额外的0,我了让最后的0可以进来。
if not stack or heights[i] >= heights[stack[-1]]:
stack.append(i)
i+=1
else:
t = stack.pop(-1)
res = max(res,heights[t]*(i-stack[-1]-1))
return res