[LeetCode] Largest Rectangle in Histogram

http://blog.csdn.net/abcbc/article/details/8943485


http://fisherlei.blogspot.com/2012/12/leetcode-largest-rectangle-in-histogram.html


循环有不同的写法

它这种i先动,j从i往左扫(往回扫)的方式,很适合第二种方法的剪枝,是从范围小到范围大,正好当后面比前面大的话,当前的i就没必要往前扫了,后面肯定比当前的i组成的面积大

一般的i,j都往后扫,不好剪枝啊,是范围大道范围小了



O(n)的解法,

http://www.geeksforgeeks.org/largest-rectangle-under-histogram/

We have discussed a Divide and Conquer based O(nLogn) solution for this problem. In this post, O(n) time solution is discussed. Like the previous post, width of all bars is assumed to be 1 for simplicity.For every bar ‘x’, we calculate the area with ‘x’ as the smallest bar in the rectangle. If we calculate such area for every bar ‘x’ and find the maximum of all areas, our task is done. How to calculate area with ‘x’ as smallest bar? We need to know index of the first smaller (smaller than ‘x’) bar on left of ‘x’ and index of first smaller bar on right of ‘x’. Let us call these indexes as ‘left index’ and ‘right index’ respectively.
We traverse all bars from left to right, maintain a stack of bars. Every bar is pushed to stack once. A bar is popped from stack when a bar of smaller height is seen. When a bar is popped, we calculate the area with the popped bar as smallest bar. How do we get left and right indexes of the popped bar – the current index tells us the ‘right index’ and index of previous item in stack is the ‘left index’. Following is the complete algorithm.

就是说,还是跟另外一个矩形题(Trapping Rain Water)类似的思路,对于每个i位置,如果都能求出以它为最小高度的时候,所能扩展的最大矩形,那么求出所有的就可以解决问题了。

那么对于每一个i位置,当向右遍历的时候,很容易知道右侧比他小的位置(因为正在往右遍历。。),那么如何快速知道左侧比它小的位置呢,那么就是用所谓的单点栈,维护一个不减栈,或者叫不减队列,里面存下标,那么每次从里面取出来小于当前i的height就是左侧位置了。


用stack保存每个i位置的最左侧小于height[i]的下标,也就是维护一个单调栈(单调不减)。

注意栈内保存的是下标,不是高度

所以栈里面就是一直pop出来小于的,那就是最左侧小于height[i]的小标了

class Solution {
public:
    int largestRectangleArea(vector<int> &height) {
        int sum = 0;
        int n = height.size();
        stack<int> index_stack;
        int i = 0;
        while (i < n) {
            if (index_stack.empty() || height[index_stack.top()] <= height[i])
                index_stack.push(i++);
            else {
                int tp = index_stack.top();
                index_stack.pop();

// 这里面geeksforgeeks的感觉不太好,没有这个循环,那么跟求解的本意是不太一样的

// 比如215523, 当55的时候,此时后面取到2,没有循环的话对于下标为3的5,求出的左边界实际上不准确的,求出面积是5.。。

// 所以循环一下更符合求解思想
                while (!index_stack.empty() && height[tp] == height[index_stack.top()]) {
                    tp = index_stack.top();
                    index_stack.pop();
                }
                sum = max(sum, height[tp] * (index_stack.empty() ? i : i - index_stack.top() - 1));
            }
        }
        while (!index_stack.empty()) {
            int tp = index_stack.top();
            index_stack.pop();
            while (!index_stack.empty() && height[tp] == height[index_stack.top()]) {
                tp = index_stack.top();
                index_stack.pop();
            }
            sum = max(sum, height[tp] * (index_stack.empty() ? i : i - index_stack.top() - 1));
        }
    
        return sum;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值