[leetcode]Largest Rectangle in Histogram

这是一道挺难得题目。传说中的单调栈。网上有个解说相当不错:http://www.cnblogs.com/lichen782/p/leetcode_Largest_Rectangle_in_Histogram.html

第二刷感悟:

这题如果不是O(n)的单调栈,其实可以用n*logn的方法做到。就是先找最小值,然后用最小值*宽度。之后左右找最小值递归。其实就是一棵建立笛卡尔树的过程。那么如果新来的柱子比栈里的高,那么栈顶作为最小值的区间已经确定,可以弹出处理;反之,还不知道区间,需要记录这个递减的栈。

====

解法里面使用了单调栈,那么它究竟保存了什么呢?我们来看一个图:这时单调栈里是index为1,4,5的元素,2和3已经pop出去了,当它遇到最后的dummy 0时,会依次计算蓝,黄和大红的方框的面积。


可以看到,其实保存了某个节点能够按照它这个高度一直延续下去计算面积的最右端。
或者说,如果j和i分别是栈里最后的两个值(j是stack.pop(),i是下一个stack.pop()),那么,j和i之间的柱子都是高度大于h[j]的,否则j早就pop出去了。
我们采用单调栈,顾名思义就是在入栈时遵循单调原则,可以求出一个元素向左(或向右)所能扩展到的最大长度,并不是说在这一段区间内是单调的,而是保证在该区间内该元素一定是最大或最小。因此,对于这道题我们可以求两次单调栈,以确定两端点一定满足题目条件。

所以最后求面积的时候,h[t] * (stack.isEmpty() ? i : (i - stack.peek() - 1));因为栈为空的时候,h[t]就是到目前为止整个数组的最小值。
那么为什么是用i而不是用t呢?
可以有几个测试用例:
1,
0,1
1,0
1,2,1
1,1,2
注意到最后一个例子时,当i指向最后的展位符0时,开始pop 2,max为2,然后pop 1。这个时候,长度应该为3,所以要从i开始计算。
另外本题重新复制了一下height数组,增加了1个长度,就是在最后放了一个0,作为哨兵,可以保证当i==heigth.length的时候,可以把之前的都给计算。

public class Solution {
    public int largestRectangleArea(int[] height) {
        int[] h = Arrays.copyOf(height, height.length+1);
        Stack<Integer> stack = new Stack<Integer>();
        int max = 0;
        int i = 0;
        while (i < h.length)
        {
            if (stack.isEmpty() || h[i] >= h[stack.peek()])
            {
                stack.push(i);
                i++;
            }
            else
            {
                int t = stack.pop();
                int tmp = h[t] * (stack.isEmpty() ? i : (i - stack.peek() - 1));
                max = Math.max(tmp, max);
            }
        }
        return max;       
    }
}

  

posted @ 2013-08-25 00:01  阿牧遥  阅读(333)  评论(0编辑  收藏  举报