LintCode 122: Largest Rectangle in Histogram (单调递增栈经典题!)

  1. Largest Rectangle in Histogram
    Given n non-negative integers representing the histogram’s bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
    Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].
    The largest rectangle is shown in the shaded area, which has area = 10 unit.

Example
Given height = [2,1,5,6,2,3],
return 10.

思路:单调递增栈。
这题实际上等价于:对每个矩形求左右最近的一个比他低的矩形的边界,然后左右两侧距离相加(还要-1,因为自身算了2遍)×该矩形高度。然后找出所有矩形中该操作的最大值。
注意:

  1. 为什么是单调递增栈而不是单调递减栈?
    因为对栈top矩形来说,我们要找左右两边最近的比他低的矩形。我们从左到右扫描,如果新的矩形比top矩形低,则新的矩形是top矩形的右边最近的比它低的元素。同时,top矩形在栈内的下面一个矩形是其左边离它最近的低的元素。
  2. 时间复杂度O(n)。因为每个元素入栈出栈一次。
  3. 注意w = s.empty() ? i : i - s.top() - 1。
    这里首先要注意stack可能会empty,如果是,则直方图宽度为i。
    若否,则直方图宽度为i-s.top()-1,因为直方图的右边界为i - 1,左边界为s.top()+1,所以宽度为(i-1)-(s.top()+1)+1=i-s.top()-1。
    注意这里的s.top()已经更新了,它实际上是pop()掉的那个s.top()的下面一个。
  4. 最右边加一个dummy,确保最后一个矩形也被考虑。但要注意for循环里面是<=len,因为加了一个dummy, 实际len的值加了1。
  5. while循环里面用>=和>都可以,效果是等价的。
    例如,nums=[5,5,5,5,5],用>=的话每个5都会挨个挨个pop掉,用>的话,所有的5是到最后一步才逐个pop掉。但效果是一样的。

代码如下:

class Solution {
public:
    /**
     * @param height: A list of integer
     * @return: The area of largest rectangle in the histogram
     */
    int largestRectangleArea(vector<int> &height) {
        int len = height.size();
        if (len == 0) return 0;
        
        int maxArea = 0;
        vector<int> height2 = height;
        height2.push_back(-1);
        
        stack<int> monoIncStack; // mono increasing stack

        for (int i = 0; i <= len; ++i) {
            while(!monoIncStack.empty() && 
                  (height2[monoIncStack.top()] >= height2[i])) {
                
                int top = monoIncStack.top();
                monoIncStack.pop();
                int h = height2[top];
                int w = monoIncStack.empty() ? i : i - monoIncStack.top() - 1; 
                //note it is not i - top - 1;
            
                maxArea = max(maxArea, h * w);
            }
            
            monoIncStack.push(i);
        }
        
        return maxArea;
    }
};

这题也可以在数组两边各加一个dummy,这样就不用判断stack.empty()了。这里要注意data.size()已经加了2。代码如下:

int LargestRec2(vector<int> &data) {
    stack<int> monoStack; //单调递增栈
    int maxV = 0;

    //add two dummy boundaries
    data.insert(data.begin(), -1);
    data.push_back(-1);

    for (int i=0; i<data.size(); ++i) {
        while(!monoStack.empty() && data[monoStack.top()]>data[i]) {
            int oldTop = monoStack.top();
            monoStack.pop();
            maxV = max(maxV, data[oldTop]*(i-monoStack.top()-1));
        }
        monoStack.push(i);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值