LeetCode84-柱状图中最大的矩形面积

LeetCode84-柱状图中最大的矩形面积

题目

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例图

输入: [2,1,5,6,2,3]
输出: 10

思路

一、暴力
两个循环,先固定一个外层循环,每次找到一个不为0的柱子,向右边遍历,遍历到最后或者遍历到高度为0的柱子停止。

public int largestRectangleArea(int[] heights) {
        if(heights.length == 0) return 0;
        if(heights.length == 1) return heights[0];
        int max = 0;
        int len = heights.length;
        for(int i = 0 ; i < len ; ++i){
            if(heights[i]!=0){
                int min = heights[i];
                for(int j = i; j < len ; ++j){
                    if(heights[j]==0)
                        break;
                    min = Math.min(min,heights[j]);
                    max = Math.max(max,min*(j-i+1));
                }
            }else{
                continue;
            }

        }
        return max;
    }

二、
另一种暴力方法
从每一个柱子向两边遍历,找到左边最后 1 个大于等于 heights[i] 的下标l,找到右边最后 1 个大于等于 heights[i] 的下标r,面积就是heights[i]*(r-l+1)

public int largestRectangleArea(int[] heights) {
        int len = heights.length;
        // 特判
        if (len == 0) {
            return 0;
        }

        int res = 0;
        for (int i = 0; i < len; i++) {

            // 找左边最后 1 个大于等于 heights[i] 的下标
            int left = i;
            int curHeight = heights[i];
            while (left > 0 && heights[left - 1] >= curHeight) {
                left--;
            }

            // 找右边最后 1 个大于等于 heights[i] 的索引
            int right = i;
            while (right < len - 1 && heights[right + 1] >= curHeight) {
                right++;
            }

            int width = right - left + 1;
            res = Math.max(res, width * curHeight);
        }
        return res;
    }

三、单调栈
以上暴力写法 Java 可以通过,但我们不妨想一下这里的双重循环是否可以优化?

我们每遍历到当前柱体 i 时:

上述写法中,我们需要再嵌套一层 while 循环来向左找到第一个比柱体 i 高度小的柱体,这个过程是 O(N) 的;
那么我们可以 O(1) 的获取柱体 i 左边第一个比它小的柱体吗?答案就是单调增栈,因为对于栈中的柱体来说,栈中前一个柱体就是左边第一个高度小于自身的柱体。
因此做法就很简单了,我们遍历每个柱体,若当前的柱体高度大于等于栈顶柱体的高度,就直接将当前柱体入栈,否则若当前的柱体高度小于栈顶柱体的高度,说明当前栈顶柱体找到了右边的第一个小于自身的柱体,那么就可以将栈顶柱体出栈来计算以其为高的矩形的面积了。

class Solution {
    public int largestRectangleArea(int[] heights) {
        int len = heights.length;
        int res = 0;
        //这里使用ArrayDeque是因为比Stack更快。
        Deque<Integer> stack = new ArrayDeque<>();

        //在柱状图两侧各设立一个高度为0的柱子,方便计算
        int[] temp = new int[len+2];
        System.arraycopy(heights,0,temp,1,len);
        len += 2;
        // 对栈中柱体来说,栈中的前一个柱体就是其「左边第一个小于自身的柱体」;
        // 若当前柱体 i 的高度小于栈顶柱体的高度,说明 i 是栈顶柱体的「右边第一个小于栈顶柱体的柱体」。
        // 因此以栈顶柱体为高的矩形的左右宽度边界就确定了,可以计算面积
        for(int i = 0 ; i  < len ; ++i){
            while(!stack.isEmpty()&&temp[i]<temp[stack.peek()]){
                int curHeight = temp[stack.pop()];
                //宽度的计算是=当前位置-左边第一个小于自身的柱体的位置-1
                int width = i - stack.peek() - 1;
                res = Math.max(res,curHeight*width);
            }
            stack.push(i);
        }
        return res;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值