LeetCode 84. Largest Rectangle in Histogram

https://leetcode.com/problems/largest-rectangle-in-histogram/

Description

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

Solution

这是直方图最大矩形面积的模板题。首先,联系到木桶的短板效应,即木桶最多能装的水的数量,由最短那块木板决定。那么同理,如果想要在直方图中得到最大矩形面积,这个矩形的高度至少可以撑满一个bar(一个bar指直方图中一个竖条)。因为如果没有撑满任何bar的话,向上扩大一点点直到撑满某个bar的高度,可以得到更大的矩形。

既然肯定会撑满某个bar,那么问题可以转化为,找到某个bar,以它的高度作为矩形的高度,看以它为中心向左右扩散,最大能得到多大的矩形。暴力枚举容易超时,这里介绍维护单调栈的算法。

class Solution:
    def largestRectangleArea(self, heights: 'List[int]') -> 'int':
        heights = [0] + heights + [0]
        stack = []
        area = 0
        
        for i in range(0, len(heights)):
            if len(stack) == 0:
                stack.append(i)
            else:
                while len(stack)>0 and heights[stack[-1]]>heights[i]:
                    top = stack.pop()
                    area = max(area, (i-stack[-1]-1)*heights[top])
                stack.append(i)
        return area
            
                    

这里以一个stack模拟一个单调栈,里面存放bar的下标,按照bar的高度是非严格递增的。然后在直方图最开始和最末尾各加入一个高度为0的bar,方便处理边界值。

处理当前下标为 i 的bar。
一、当栈为空时,直接将下标 i 压入栈中。
二、当栈内有元素时,如果栈顶元素不高于 heights[i],直接将 i 压入栈中;
否则,假设栈顶元素是 top,对应的 bar 的高度是 heights[top]。将此元素弹出栈,此时栈顶元素假定为 tmp_top,然后可以得到一个显然的性质:下标 tmp_top 到下标 i 之间的所有 bar (不包含两个端点)的高度,都不低于 heights[top]。分两步证明:

  1. 假设 top~i 之间有 bar 的高度小于 heights[top],那么 top 这个元素会被弹出栈,不应该存在。
  2. 假设 tmp_top~top 之间有 bar 的高度小于 heights[top],那么不满足栈的单调性,显然不成立,得证。

然后下标 tmp_top 到下标 i 之间的所有 bar,可以组成一个高度为 heights[top] 的矩形。面积为 heights[top] * (i-tmp_top-1)。与当前记录的最大面积比较并更新即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值