剑指 Offer II 039. 直方图最大矩形面积

题目描述:

给定非负整数数组 heights ,数组中的数字用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例:
在这里插入图片描述
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

解法: 单调栈

根据木桶效应,在相邻的若干矩形中,能够构成的最大矩形的高取决于这些矩形中最矮的那个。 因此在一片相邻的矩形中,只要找到最矮的,其他矩形的高就可以不用考虑。

因此可以想到(可能想不到)使用单调栈的方法,构建一个单调递增的栈。如果遇到的柱子高度比栈顶柱子的高度要高,就直接入栈,维持栈的单调递增特性就好。
(为什么是单调递增栈? 因为这样的话,后入栈的元素都会更大,在计算矩形面积的时候,从栈中间到栈顶围成的矩阵高度就是栈中间的高度,而宽度就是两个下标的差值,直接相乘就可以算出面积。)

核心是 遇到的柱子高度如果比栈顶的柱子高度要低,那么如何操作。

根据单调栈的思想,如果遇到的柱子比栈顶柱子低,就需要对栈中存在的元素进行计算,出栈,直到栈空或者栈顶元素比新遇到的柱子高。 这样才可以维持栈的单调性。

因此, 整个方法的主要步骤是:

  1. 新遇到的柱子比栈顶柱子高,或者此时栈为空,新柱子的下标直接入栈;
  2. 新遇到的柱子更低,栈开始弹出元素,直到栈为空,或者直到遇到栈顶的柱子比新遇到的柱子要高。 在栈不断弹出元素的过程中,就可以针对每个弹出的元素(也就是柱子下标),针对每个柱子计算以这个柱子为高的面积。 这个面积的计算可能稍微有一些绕,首先,这个面积的高就是从栈中弹出的柱子的高,但是**这个面积的宽并不是新柱子与这个柱子下标的差值。**新柱子到这个柱子下标的差值可能只是面积的右边的一部分,这个柱子左边可能还有比它高的柱子! 但是前面提到是单调递增栈,左边的不是都比它更矮吗?这里很关键的一点是:左边比它高的柱子压根没进栈 ,因为要维护栈的单调性! 因此,这个矩形的宽其实是这个柱子在栈中左侧的柱子(此时是栈顶)下标与新柱子下标的差值。 我们用i来表示新遇到的柱子下标,cur表示栈顶柱子下标,pre表示被cur压在底下那个柱子(次栈顶),在计算以cur柱子为高的面积时,宽其实是i-(pre+1)=i-pre-1。

tips:

  • 可以一开始在栈中放入一个-1,表示栈空,简化过程。
  • 可以在柱子列表尾部加入一个-1,这样在遍历到尾部时,可以一把子把前面的算完。
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int> s;
        // 通过一个单调栈实现
        int n=heights.size();
        if(n==0) return 0;
        heights.emplace_back(-1);
        s.push(-1);
        // 放一个-1表示栈底
        int res=0;
        for(int i=0; i<=n; i++){
            // s存的是height的下标
            while(s.top()!=-1 && heights[i]<heights[s.top()]){
                // 如果等于-1,遇到栈底,栈为空,直接push
                int height=heights[s.top()];
                s.pop();
                int width=i-(s.top()+1);
                res=max(res, height*width);
            }
            s.push(i);
        }
        return res;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值