LeetCode —— Largest Rectangle in Histogram

链接:http://leetcode.com/onlinejudge#question_84

原题:

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.

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

思路:

我是用二分法做的。

1. 选择中间一个元素,那么向两边遍历,找到最大矩形,复杂度为O(N);

2.不选择中间一个元素,那么递归找左右两支的最大矩形

所以总的复杂度为O(nlogn)


在网上搜了一把,发现有一个O(N)的方法,额外用一个stack记录,挺巧妙。

我这种脑子是想不出来的,呵呵。


代码:

class Solution {
public:
    int largestRectangleArea(vector<int> &height) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        return maxArea(height, 0, height.size());
    }

private:
    int maxArea(const vector<int> &height, int left, int right) {
        if (right <= left)
            return 0;
        
        int mid = (left + right) / 2;
        int curMin = height[mid];
        int curMaxArea = 0;
        int curLeft = mid, curRight = mid;
        while (curLeft >= left && curRight < right) {
            for (; curLeft >= left; curLeft--)
                if (height[curLeft] < curMin)
                    break;
            for (; curRight < right; curRight++)
                if (height[curRight] < curMin)
                    break;
            int temp = (curRight - curLeft - 1) * curMin;
            if (curMaxArea < temp)
                curMaxArea = temp;
            
            if (curLeft < left || curRight >= right)
                break;
            if (height[curLeft] >= height[curRight])
                curMin = height[curLeft];
            else
                curMin = height[curRight];
        }
        while (curLeft >= left) {
            curMin = height[curLeft];
            for (; curLeft >= left; curLeft--)
                if (height[curLeft] < curMin)
                    break;
            int temp = (curRight - curLeft - 1) * curMin;
            if (curMaxArea < temp)
                curMaxArea = temp;
        }
        while (curRight < right) {
            curMin = height[curRight];
            for (; curRight < right; curRight++)
                if (height[curRight] < curMin)
                    break;
            int temp = (curRight - curLeft - 1) * curMin;
            if (curMaxArea < temp)
                curMaxArea = temp;
        }
        
        int leftMax = maxArea(height, left, mid);
        if (curMaxArea < leftMax)
            curMaxArea = leftMax;
        int rightMax = maxArea(height, mid+1, right);
        if (curMaxArea < rightMax)
            curMaxArea = rightMax;
            
        return curMaxArea;
    }
};


再次做这道题目,就试了一下O(N)的方法,

如果暴力,就是枚举所有柱子,以它为高,先左右两边分别找比它小的边界,然后算面积,这样是O(N^2)。

但是有一种数据结构可以在O(N)时间里面找到边界(所有元素),叫increasing stack,单调递增子段。

具体作法是:如果栈顶元素值不大于当前值,就把当前值push到栈里面;如果大于当前值,那么凡是栈里面

比当前值大的元素,都是以当前值为右边界,做边界当然是栈里比它前面一个。So nice。

P.S. 不要忘了最后清空栈。


代码:

class Solution {
public:
    int largestRectangleArea(vector<int> &height) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (height.size() == 0)
            return 0;
        
        stack<int> indexStack;
        indexStack.push(-1);
        indexStack.push(0);
        
        int maxArea = 0;
        for (int i=1; i<height.size(); i++) {
            int cur = height[i];
            while (indexStack.size()>1 && cur < height[indexStack.top()]) {
                int maxHeight = height[indexStack.top()];
                indexStack.pop();
                int curArea = maxHeight * (i - indexStack.top() - 1);
                if (curArea > maxArea)
                    maxArea = curArea;
            }
            indexStack.push(i);        
        }
        
        while (indexStack.size() > 1) {
            int maxHeight = height[indexStack.top()];
            indexStack.pop();
            int curArea = maxHeight * (height.size() - indexStack.top() - 1);
            if (curArea > maxArea)
                maxArea = curArea;
        }
        
        return maxArea;
    }
};



你可能感兴趣的:(LeetCode,二分法)