【刷题1】LeetCode 84. 柱状图中最大的矩形 java题解

题目

https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
在这里插入图片描述

二刷

参考:https://www.sohu.com/a/454782608_120437685
构建一个单调递增的单调栈。求以栈顶高度为高的矩形宽度,就要找到左边和右边第一个小于它的元素。左边界(开区间)是前一个栈中元素,右边界(开区间)是右边第一个小于它的元素。

class Solution {
    public int largestRectangleArea(int[] heights) {
        int[] height=new int[heights.length+2];
        height[0]=0;
        height[heights.length+1]=0;//数组首尾添加0
        for(int i=0;i<heights.length;i++){
            height[i+1]=heights[i];
        }
        LinkedList<Integer> stack=new LinkedList<>();
        stack.addLast(0);
        int max=0;
        for(int i=1;i<height.length;i++){
            while(!stack.isEmpty()&&height[stack.peekLast()]>=height[i]){
                int index=stack.removeLast();
                int h=height[index];//要计算这个高度能勾勒的矩形面积
                int len=i-index;//宽度
                if(!stack.isEmpty()){
                    len=i-stack.peekLast()-1;
                }
                max=Math.max(max,h*len);
            }
            stack.addLast(i);
        }
        return max;
    }
}

方法一:单调栈

在这里插入图片描述

分析

暴力解法:矩形面积=底*高。底不好固定,所以按高度固定。对于不同的高度,向左右扩散直到有小于它的高度,就可以知道这个高度能勾勒的最大矩形面积。时间复杂度是O(n²)。
优化的思路是以空间换时间。

特殊情况
1.遍历完成后,栈顶元素一定可以扩散到数组末尾
2.弹出栈顶以后栈为空,当前数一定可以扩散到数组的最左边
3.栈中存在连续的高度相等的元素,新栈顶和当前栈顶一样时,做特殊的判断。不过不做也行,虽然计算不准确,但不影响最终结果。

复杂度

时间复杂度:O(N)。
空间复杂度:O(N)。

代码

class Solution {
    public int largestRectangleArea(int[] heights) {
        int len=heights.length;
        if(len==0) return 0;
        if(len==1) return heights[0];
        Deque<Integer> stack=new LinkedList<>();
        int area=0;
        for(int i=0;i<len;i++){
            while(!stack.isEmpty()&&heights[i]<heights[stack.peekLast()]){
                int height=heights[stack.removeLast()];
                while(!stack.isEmpty()&&height==heights[stack.peekLast()]){
                    stack.removeLast();
                }
                int width;
                if(stack.isEmpty()){
                    width=i;
                }
                else{
                    width=i-stack.peekLast()-1;
                }
                area=Math.max(area,width*height);
            }
            stack.addLast(i);
        }
        while(!stack.isEmpty()){
            int height=heights[stack.removeLast()];
            while(!stack.isEmpty()&&height==heights[stack.peekLast()]){
                stack.removeLast();
            }
            int width;
            if(stack.isEmpty()){
                width=len;
            }
            else{
                width=len-stack.peekLast()-1;
            }
            area=Math.max(area,width*height);
        }
        return area;
    }
}

结果

在这里插入图片描述

方法一的优化:哨兵

哨兵优化
在这里插入图片描述

class Solution {
    public int largestRectangleArea(int[] heights) {
        int len=heights.length;
        if(len==0) return 0;
        if(len==1) return heights[0];
        Deque<Integer> stack=new LinkedList<>();
        int area=0;
        int[] he=new int[len+2];
        he[0]=0;
        he[len-1]=0;
        for(int i=0;i<len;i++){
            he[i+1]=heights[i];
        }
        stack.addLast(0);
        for(int i=1;i<len+2;i++){
            while(he[i]<he[stack.peekLast()]){
                int height=he[stack.removeLast()];
                int width=i-stack.peekLast()-1;//这很关键!!!
                area=Math.max(area,width*height);
            }
            stack.addLast(i);
        }
        return area;
    }
}

在这里插入图片描述

class Solution {
    public int largestRectangleArea(int[] heights) {
        int len=heights.length;
        int max=heights[0];
        int[] h=new int[len+2];
        h[0]=0;
        h[len+1]=0;
        for(int i=1;i<=len;i++){
            h[i]=heights[i-1];
        }
        LinkedList<Integer> stack=new LinkedList<>();
        //单调增栈,存放index
        for(int i=0;i<len+2;i++){
            if(stack.isEmpty()||h[stack.peek()]<=h[i]){
                stack.push(i);
            }
            else{
                while(!stack.isEmpty()&&h[stack.peek()]>h[i]){
                    int index=stack.pop();//他找到了自身高度的最大面积
                    int left=index;
                    if(!stack.isEmpty()){
                        left=stack.peek()+1;                   
                    }
                    int right=i-1;//i的高度小于
                    max=Math.max(max,h[index]*(right-left+1));
                }
                stack.push(i);
            }
        }
        return max;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值