您的位置:首页 > 其它

LeetCode_Stack_Largest Rectangle in Histogram

2015-06-28 01:25 204 查看

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_stackindex\_stack 存储递增柱的索引值(之后计算覆盖矩形面积的长),栈 height_stackheight\_stack 存储递增柱的值(之后计算覆盖矩形面积的高)。所以我们只去计算栈中柱所覆盖的最大面积。面积计算的公式就是:S=(i−(left−1)−1)∗height_stack.pop() S= (i - (left-1) -1) * height\_stack.pop() 。这里(i−(left−1)−1)(i - (left-1) -1) 就是覆盖矩形面积的长, i 是现在遍历到的柱的索引值,left−1left-1 是index_stackindex\_stack 的栈顶元素减一。height_stack.pop()height\_stack.pop()就是存柱值的栈顶元素。

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

那么2因为递减趋势,不加入栈中,开始计算面积。 (i−(left−1)−1)(i - (left-1) -1) 中的 ii 就是2所在的索引值,left−1left-1 是5所在的索引值。height_stack.pop()height\_stack.pop() 就是6。这时计算的就是6这个柱的面积,把这个面积和当前最大面积比较,比当前面积大就替换。然后弹出6柱和其索引。

比较指针所在的2柱和此时栈顶元素5,发现仍是递减,那继续计算面积,就是(2柱索引值−1柱索引值−1)∗5(2柱索引值 - 1柱索引值 -1)* 5,就是5向右延伸到6的面积。比较面积替换,然后弹出5柱和其索引。

比较指针所在的2柱和此时栈顶元素1,发现此时是递增,那么把2柱加入 height_stackheight\_stack,同时把 leftleft 加入 index_stackindex\_stack 中。这里要注意,为什么不加入2柱所在的索引,而要加入 leftleft。原因很简单,这里 leftleft 是 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. 算法评估



希望大家多多指正交流。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: