LeetCode_Stack_Largest Rectangle in Histogram

84. Largest Rectangle in Histogram

这里写图片描述


1. 问题描述:

输入是一个int数组,代表如图的直方图。要求输出是直方图能够覆盖的最大面积。

2. 解题思路:

直白的看这道题,最大的面积一定是从某个柱出发,向左向右延展,然后得到最大的面积。于是问题来了,从哪个柱开始延展,延展到哪个柱就能得到最大的面积。

首先,如题目图中示例,我们先把目光聚焦到5,6,2这三根柱,忽略掉其他的柱。图中已经画出5,6覆盖了最大面积,想象如果继续向右延伸到2,那么2这根柱势必拉低了5,6覆盖面积的成果。但如果是5,6,7,那么势必要向右延伸到7,并且5,6,7覆盖的面积一定大于5,6覆盖的面积。这样我们就得出一个结论:如果遍历到下个柱是递增趋势,那么一定要延展到下一个柱。

得到这个结论之后,题目就好解了。为了好理解这里的解决思路,我们使用了两个栈,栈 index_stack 存储递增柱的索引值(之后计算覆盖矩形面积的长),栈 height_stack 存储递增柱的值(之后计算覆盖矩形面积的高)。所以我们只去计算栈中柱所覆盖的最大面积。面积计算的公式就是: S=(i(left1)1)height_stack.pop() 。这里 (i(left1)1) 就是覆盖矩形面积的长, i 是现在遍历到的柱的索引值, left1 index_stack 的栈顶元素减一。 height_stack.pop() 就是存柱值的栈顶元素。

拿题目图中示例演示其中一个阶段。当1,5,6在栈中,此时指针已经遍历到2。

  1. 那么2因为递减趋势,不加入栈中,开始计算面积。 (i(left1)1) 中的 i 就是2所在的索引值,left1 是5所在的索引值。 height_stack.pop() 就是6。这时计算的就是6这个柱的面积,把这个面积和当前最大面积比较,比当前面积大就替换。然后弹出6柱和其索引。
  2. 比较指针所在的2柱和此时栈顶元素5,发现仍是递减,那继续计算面积,就是 (211)5 ,就是5向右延伸到6的面积。比较面积替换,然后弹出5柱和其索引。
  3. 比较指针所在的2柱和此时栈顶元素1,发现此时是递增,那么把2柱加入 height_stack ,同时把 left 加入 index_stack 中。这里要注意,为什么不加入2柱所在的索引,而要加入 left 。原因很简单,这里 left 是 5 柱所在的索引值,可以当成 5,6 柱现在柱高都是2。当指针扫到最后为空时,计算2柱覆盖面积时,覆盖矩阵的长度要包括5和6。
    大致思路就是这样,代码具体的还要注意边界的处理。这里是用了两个栈,其实也可以只用一个栈,减少算法的空间复杂度。

3. java代码

public class Solution {
    public int largestRectangleArea(int[] height) {
        if(height.length == 0)
            return 0;
        int largest_area = 0; 

        Stack<Integer> height_stack = new Stack<Integer>();//存放递增的柱
        Stack<Integer> index_stack = new Stack<Integer>();//存放递增柱的索引

        for(int i=0;i<height.length;i++){
            if(height_stack.empty() || height_stack.peek()<=height[i]){ //增加递增柱
                index_stack.push(i);
                height_stack.push(height[i]); 
            } else { //error 
                int left = 0; //左边界
                while(!height_stack.empty() && height_stack.peek()>height[i]){//依次弹出栈顶元素,直到栈顶元素小于当下索引的元素
                    left = index_stack.pop();
                    int cur_area = (i - (left-1) -1) * height_stack.pop(); //跨度 i - j - 1
                    if(cur_area>largest_area) {
                        largest_area = cur_area;
                    } 
                }

                height_stack.push(height[i]);
                index_stack.push(left);
            }
        }

        while(!height_stack.empty()){
            int cur_area = (height.length - (index_stack.pop()-1)-1) * height_stack.pop();
            if(cur_area>largest_area){
                largest_area = cur_area;
            }
        }
        return largest_area;
    }
}

4. 算法评估

这里写图片描述


希望大家多多指正交流。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值