Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3]
.
The largest rectangle is shown in the shaded area, which has area = 10
unit.
Example:
Input: [2,1,5,6,2,3]
Output: 10
LeetCode:链接
这里就用到了单调栈,我们可以花费一点空间,用一个栈来维护一组下标,对于栈中的每一个下标所对应的元素。
1)如果当前元素比栈顶元素大,那就入栈,因为有可能出现更大的矩形。
2)如果当前元素比栈顶元素小,此时最大矩形的高度就变矮了,所以应该把之前栈里的元素都弹出来依次用自身的高度计算能达到的最大矩形面积,因为不一定哪个长宽比相乘就是最大的面积,所以都要计算。直到当前元素比栈顶元素大,说明又有可能出现更大的矩形了。
3)在矩形高度的末尾添加一个-1,这样方便计算以末尾为高度的最大矩形。最后剩下的高度,肯定是最矮的高度,矩形面积的宽度可以覆盖整个横轴。
我的总结就是,如果比高度比当前元素大,还有出现最大面积的可能,就先保留,但是如果比当前元素小,就没有必要保留了。
还是模拟一下过程,对于图中的测试样例。创建一个stack,然后进行遍历
- 第一个元素,直接入栈,栈中元素为0(2),栈中保存下标,括号里面表示对应的元素
- 第二个元素,比第一个元素小,弹出第一个元素,弹出第一个的元素的时候,要计算它左右能达到的面积,2对应的最大面积为2*1,更新面积,然后第二个元素入栈,栈中元素1(1)
- 第三个元素,入栈,栈中元素1(1)、2(5)
- 第四个元素,入栈,栈中元素1(1)、2(5)、3(6)
- 第五个元素,比栈顶的要小,所以要出栈,首先3出栈,6对应的左边第一个比他小的就是下标2对应的5,右边就是当前的下标对应的2,所以面积为6,然后5出栈,他左边第一个比他小的是下标1对应的1,右边则是当前下标对应的2,所以更新面积得到10。然后入栈,栈中元素1(1)、4(5)
- 最后一个元素3,入栈,栈中元素1(1)、2(5)、3(6),然后依次弹出,并更新面积。
class Solution(object):
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
if not heights:
return 0
stack = []
#添加-1是为了判断是不是进行到了最后一个
heights.append(-1)
ans = 0
for i in range(len(heights)):
#如果栈为空或者当前柱比栈顶柱要高,入栈
if not stack or heights[i] > heights[stack[-1]]:
stack.append(i)
else:
#如果栈不为空并且当前柱比栈顶柱要低,出栈,更新结果。
while len(stack) != 0 and heights[i] <= heights[stack[-1]]:
h = heights[stack.pop()]
# 如果左边界存在就是栈顶否则就是-1
left = stack[-1] if len(stack) != 0 else -1
w = i - left - 1
ans = max(ans, h*w)
stack.append(i)
return ans