84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
这道和接雨水有点像,但是真的难,开始的时候想到每一个列举单个最大面积,但是会超时。
还是看一下列举面积的情况:
- 首先选定一个柱子,左右分别寻找比这个主子高度低的索引坐标,大于等于本柱子高度则跳过。
- 找到左右都比其大于等于的最远坐标left, right。使用 right - left +1得到底边的长度,再乘以本柱子的高度,得到单个柱子的最大面积。
具体的实现代码如下:
from typing import List
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
size = len(heights)
res = 0
for i in range(size):
left = i
cur_height = heights[i]#如果左边的高度大于等于本柱子的高度,下标左移
while left > 0 and heights[left - 1] >= cur_height:
left -= 1
right = i#如果右边的高度大于等于本柱子的高度,下标右移
while right < size - 1 and heights[right + 1] >= cur_height:
right += 1
max_width = right - left + 1#计算底面的长度
res = max(res, max_width * cur_height)#算出本次以本柱子为高度,最大的面积,迭代更新
return res
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/bao-li-jie-fa-zhan-by-liweiwei1419/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
但是,从上面的例子可以发现,其实只用找一遍就可以,例如 我们可以存储一个递增的高度,如果之后要加进来的高度不是递增的,就表示找到了一个有边界。与此同时,我们由于栈中的高度是递增的,所以栈中的每个高度的左边界就是其左边的值的下标,这么一来,左右边界都确定了,高度也确定,那么就可以计算出每一个的面积,迭代算出最大值。
例如上图所示:[1, 5, 6]是目前栈中所存储的三个高度,之后的2 < 6,不能假如栈中,这个时候依次弹出栈中的值,比如弹出6,因为栈是一个单向递增栈,所以6的左边界就是5.所以我们可以知道高度位为6 的面积底边就是2下标减去5的下标减一等于1,乘以高度6,得到面积6。
弹出6之后,栈中只有[1, 5],由于待加入的 2 < 5,所以2不能入栈,高度5的面面积待计算,从栈中弹出5,5的左边界为1,右边界还是为不能加入栈的2,因为递增栈,6是大于5的所以右边界还是为2,两个下标之差减一得到底边长度,乘以高度5,得到面积10。
注意:
1.弹栈的时候,栈为空;
2.遍历完成以后,栈中还有元素
弹栈的时候,如果栈为空,就没有上一个记录的左边界值,所以在原始列表开头添加一个“哨兵” [0],防止原始列表内的值在栈内全部弹出后,找不到左边界。
加入列表中的值全为递增,那么我们将所有值都入栈后找不到比栈中最上面小的值,于是就出不了栈。所以在原始列表的尾端加上一个“ 哨兵”,此处为[ 0 ]。这样列表内的值都可以出栈了。
from typing import List
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
stack = []
heights = [0] + heights + [0]#建立一个含有哨兵的列表,首尾哨兵,假如是递增的列表数据,也可以弹栈
res = 0
for i in range(len(heights)):
#栈不为空,即有左边界,并且带入栈的高度比栈顶高度小,所以不能入栈,需要出栈计算底边长度和面积
while stack and heights[stack[-1]] > heights[i]:
temp = stack.pop()#弹栈,这里面记录的是高度的下标
#底边长度等于 i(右边界) - stack[-1](左边界) - 1
res = max(res, (i - stack[-1] -1) * heights[temp])#计算最大面积
stack.append(i)#如果栈为空则将此下标入栈
return res
if __name__ == "__main__":
s = Solution()
print(s.largestRectangleArea([2,1,5,6,2,3]))