LeeCode_84. 柱状图中最大的矩形(单调栈)

一、介绍

1.题目描述

题目链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/

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

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

2.测试样例

[2,1,5,6,2,3] # 10

[2,4] # 4

[1,2,2] # 4

[2,1,2] # 3

[5,4,1,2] # 8

二、思路(暴力→单调栈)

可以很容易想到的是暴力解法,以[5,4,1,2]为例,先看5,左右没有≥5的数,因此对于5来说,最大大小是1×5=5;对于4,左右可以得到两列连续的4(∵左侧5>4),所以对于4来说最大大小是 2×4=8;同理,对于1 ,max=4×1,对于2,max=1×2。最大是8。但是这个方法的复杂度会达到n²,超出时间限制。
对于这种到两侧找更小边界的问题,想到单调栈
为实现递增,当碰到比当前小的数,就要弹出栈顶,循环判断直至栈为空或没有比当前更大的数,再将当前的压入。
对于弹出的数,其一定有左边界,而右边界就是当前数。于是可以计算弹出数能得到的最大矩阵大小。
当弹出的已经是栈中最后一个元素,则说明左侧没有更大的数了,开头到当前数的距离(即当前数-0)作为宽。
当弹出的不是最后一个元素,则弹出后的新栈顶是左边界,(当前数-左边界)为宽
遍历完成后,栈中会剩下一些元素,需要另行处理。为了简化操作,将他们统一处理,可以在数组末尾加上数字0,则剩余的数也会弹出并计算答案

三、题解(单调栈🟡)

  1. 用指针 i 遍历数组,i 表示下标
  • 当栈为空,推入 i
  • 当栈非空,看下个是否高于栈顶指向的元素的高度
    • 下一个更高或一样高,继续推入
    • 下一个低,弹出栈顶并计算结果
  1. 弹出时,计算宽×高
  • 若弹出后栈为空,则该元素前的所有元素都小于它。宽为 i
  • 若弹出后栈不为空,则当前栈顶至 i 都小于该元素的高。宽为 i - stk.top()+1
  1. 重复12步骤

注意事项:

  • 在末尾加入0元素,就不用遍历完再处理多余元素

参考链接:

https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/zhu-zhuang-tu-zhong-zui-da-de-ju-xing-by-leetcode-/

https://www.bilibili.com/video/BV1jV411S7WJ?share_source=copy_web

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int> stk;
        heights.push_back(0);
        // ans 记录答案
        int n=heights.size(),ans=0;
        for(int i=0;i<n;i++){
            while(!stk.empty()&&heights[i]<heights[stk.top()]){
                // 当栈不为空且下一个比栈顶低
                int t=stk.top();
                stk.pop();
                // 弹出后为空,则宽为 i
                if(stk.empty()){
                    ans=max(ans,i*heights[t]);
                }
                // 弹出后不为空,则宽为 i-(stk.top()+1)
                else ans=max(ans,(i-(stk.top()+1))*heights[t]);
            }
            // 栈为空或当前i指向的柱更高,推入下标
            stk.push(i);
        }
        return ans;
    }
};

image-20210914235900379

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值