[leetcode] Largest Rectangle in Histogram 解题报告

题目链接:https://leetcode.com/problems/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.

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


思路:我记得很清楚昨天晚上睡觉之前写了一篇这题的解题报告,怎么今天一看没了呢?好吧,重写写一篇吧!


这题的一个基本思想是以每一个bar为最低点,向左右遍历直到遇到比他小的bar或边界。这样就能找到一个此bar为最低点的矩形面积。遍历所有的bar之后即可找到最大的矩形面积。但是向左右遍历寻找比他小的bar的时间复杂度是O(n),在加上遍历一遍所有的bar,总的时间复杂度将为O(n*n),是无法通过所有数据的。因此我们需要寻找一种时间复杂度更低的寻找一个bar左右边界的算法。在网上流传了一个设计极其巧妙的方法,借助一个stack可以将时间复杂度降为O(n),真是让人叹为观止,原作者好像是个老外。

这种算法的思想是维护一个递增的栈,这个栈保存了元素在数组中的位置。 这样在栈中每一个左边的bar都比本身小,所以左边就天然有界了,也就是左边界就是左边的一个bar。遍历一遍height数组,在将height数组入栈的时候,如果当前元素height[i]比栈顶元素小,则我们又找到了栈顶元素的右边界。因此我们在此时就可以计算以栈顶元素为最低bar的矩形面积了,因为左右边界我们都已经找到了,而且是在O(1)的时间复杂度内找到的。然后就可以将栈顶元素出栈了。这样每出栈一个元素,即计算以此元素为最低点的矩形面积。当最终栈空的时候我们就计算出了以所有bar为最低点的矩形面积。为保证让所有元素都出栈,我们在height数组最后加一个0,因为一个元素要出栈必须要遇到一个比他小的元素,也就是右边界。

现在我们以height[2, 1, 5, 6, 2, 3]为例来分析其入栈出栈操作是如何完成的:

1. 首先栈为空,则2在数组中的位置0入栈,现在栈顶为元素2在数组中的位置0

2. 遍历到1的时候,发现1比栈顶元素height[0]小,因此栈顶元素height[0]的左右边界都找到了,将0出栈,并计算以栈顶元素height[0]为最低bar的矩形面积为2。0出栈之后栈为空

3. 此时将元素1的位置1入栈,此时栈顶为元素1在数组中的位置1

4. 再将元素5的位置2入栈,此时栈顶为元素5在数组中的位置2

5. 再将元素6的位置3入栈,此时栈顶为元素6在数组中的位置3

6. 遍历到2的时候发现2比栈顶元素height[3]即6小,因此6的左右边界都已找到,此时即可将3出栈,并计算以栈顶元素height[3]为最低点的矩形面积为6。此时栈顶为元素5在数组中的位置2。

7. 然后遍历到元素2再和栈顶元素比较,发现卧槽还是不能入栈,因此只能再把栈顶元素赶出来了。然后2出栈,并计算以5为最低点的矩形面积,此时矩形的宽度为2,因为元素5在数组中的位置为2,元素2在数组中的位置为4。因此以5为最低点的面积为5*2 = 10。此时栈顶为元素1在数组中的位置1。

8. 然后2再和栈顶1元素相比较发现,啊!终于碰到一个比我小的了,然后2的位置4就入栈做了栈顶

9. 再将3的位置5入栈,此时栈顶为3的位置5

10. 此时遍历到了我们自己加进去的0,比较发现0比栈顶元素小,然后栈顶5出栈,并计算以3为最低点的矩形面积为3。此时栈顶元素为4。

11. 将0和栈顶的值2比较,发现0比栈顶值小,因此4出栈,并计算以2为最低点的矩形的面积。2的右边界是0, 0元素在数组中的位置为6, 2的左边界是元素1,元素1在左边的1,因此以元素2为最低点的矩形面积为2*3 = 6。此时栈顶为元素1在数组中的位置1

12. 再将1出栈,计算出面积为1

因此我们可以看出,最大的面积为10。以上就是在O(n)时间复杂度内完成了寻找矩形最大面积的任务。

代码如下:

class Solution {
public:
    int largestRectangleArea(vector<int>& height) {
        stack<int> st;
        height.push_back(0);
        const int len = height.size();
        int i =0, sum = 0;
        while(i < len)
        {
            if(st.empty() || height[i] > height[st.top()])
            {
                st.push(i);
                i++;
            }
            else
            {
                int top = st.top();
                st.pop();
                sum = max(sum, height[top] * (st.empty()?i:(i-st.top()-1)));
            }
        }
        return sum;
    }
};
参考:http://www.geeksforgeeks.org/largest-rectangle-under-histogram/

http://www.cnblogs.com/lichen782/p/leetcode_Largest_Rectangle_in_Histogram.html














你可能感兴趣的:(LeetCode,算法,array,数组,stack)