leetcode-84.柱状图中最大的矩形

84.柱状图中最大的矩形

题目要点

在这里插入图片描述

关于求解这道题有两点

(1)是多个柱子组成的矩形的高度,一定是由最低的一根柱子决定的
以当前柱子为最低高度,遍历整个数组,求出所有的面积可能
矩形面积=最低柱子高度*柱子数(大于等于最低高度且互相相邻)
(2)如何确定对应矩形的柱子数
以当前柱子i为最低高度,则需要找到对应大于等于当前柱子i的柱子数,分别向左和向右,找到柱子高度小于当前柱子高度的坐标left和right,right-left+1就是对应柱子数

解法

方法1-直接暴力求解

public int largestRectangleArea(int[] heights) {
    int max=0;
    for(int i=0;i<heights.length;i++){
        int left=i;
        int right=i;
        while(left-1>=0&&heights[left-1]>=heights[i]) left++;//往左找到坐标
        //往右找到坐标
        while(right+1<heights.length&&heights[right+1]>=heights[i]) right++;
        max=Math.max(max,heights[i]*(right-left+1));
    }
    return max;
}

显然两层for循环,时间复杂度 O(n^2)

方法2-优化暴力法

优化方式-记录之前的left和right
以left[]为例
left[i-1], 如果heights[i]>=heights[i-1],那么heights[i]一定大于等于left[i-1]和i之间的柱子,直接和left[i-1]比较就行

public int largestRectangleArea2(int[] heights) {
    int max=0;
    int left[]=new int [heights.length];
    int right[]=new int [heights.length];
    for(int i=0;i<heights.length;i++){//往左找到坐标
        int index=i-1;
        while(index>=0&&heights[index]>=heights[i]) index=left[index];

        left[i]=index;

    }
    //注意这里要从后往前找  
    for(int i=heights.length-1;i>=0;i--){//往右找到坐标
       int index=i+1;
        while(index<heights.length&&heights[index]>=heights[i]) index=right[index];
        right[i]=index;
        max = Math.max(max, (right[i] - left[i] - 1) * heights[i]);
    }

    return max;
}

方法3-单调递增栈

通过单调递增栈,可以只使用O(n)的代价得到对于一个柱面高度,不小于这个高度的柱面数量
向右遍历时面积求法
area= (i−stack[top−1]−1)×heights[stack[top]]
弹出一个数,就会计算一次面积
需要入栈的数i,heights[i]<=heights[stack[top] 这是弹出栈顶元素的条件
stack[top−1] 栈顶元素的前一个数 stack[top−1]< stack[top]
就这样刚好找到了 栈顶元素的left和right
遍历完成后,弹出所有数据
area= heights[stack.pop()]*(heights.length-stack[top−1]-1)

heights [2,4,6,5,3]
从前往后走
加入2 stack [-1,0]
加入4 stack [-1,0,1]
加入6 stack [-1,0,1,2]
加入5(5<6) 弹出6 大于等于6的柱面长度为 heights[2]=6   area=6*(3-1-1) =6
stack [-1,0,1,3]
加入3 弹出5 heights[1]=4是小于5的第一个左边数 heights[4]=3是小于5 第一个右边的数
area=  (第一个右边的数-第一个左边数-1)*5  =2*5
stack [-1,0,1,4]
弹出4 area=4*(4-0-1)
stack [-1,0,4] 
此时走到了尾部  需要弹出剩下的数据
由于是单调递增栈 
对于此时栈中存在元素,它一定小于后面所有元素
弹出3 
area=  (5 -0-1)*3 =3*4
stack [-1,0] 
弹出0 
area=  (5-(-)-1)*2 =5*2
 stack [-1] 
此时得到结果 12

根据上述例子,可知通过单调栈

public int largestRectangleArea3(int[] heights) {//单调栈
    int max=0;
    Stack<Integer> stack=new Stack();
    stack.push(-1);
    for(int i=0;i<heights.length;i++){//往左找到坐标

        while(stack.peek()!=-1&&heights[i]<=heights[stack.peek()]) {
            max=Math.max(max,heights[stack.pop()]*(i-stack.peek()-1));
        }
         stack.push(i);
    }
    while(stack.peek()!=-1) {
        max=Math.max(max,heights[stack.pop()]*(heights.length-stack.peek()-1));
    }

    return max;
}

遍历数组一遍,时间复杂度O(n)

参考:leetcode上的解法
https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/zhao-liang-bian-di-yi-ge-xiao-yu-ta-de-zhi-by-powc/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值