[C++]LeetCode: 133 Largest Rectangle in Histogram(最大矩形面积)

来源:互联网 发布:化妆品成分知多少 编辑:程序博客网 时间:2024/05/02 06:11
题目:

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.

Anwser 1: Brute Force

思路:穷举法,对于直方图的每一个bar, 我们穷举所有的左边界,将面积最大的那个记录下来。时间复杂度为O(N^2).但是单纯的穷举法在leetcode会TLE. 所有我们需要一些剪枝的方法,比如找到合适的右边界。我们发现当height[k] >= height[k-1]时,无论左边界取什么值,选择height[k]作为右边界总会比选择height[k-1]所形成的面积大。因此,在选择右边界时,我们首先找到一个height[k] < height[k-1]的k, 然后取k-1作为右边界,跳过中间的bar, 然后穷举所有的左边界,找到最大面积。

穷举法还有一个思路,就是以当前bar为矩形高度,然后左右两个指针分别向数组两边移动,直到高度低于当前bar高度截止,然后用当前bar的高度乘以两边走的宽度就是最大面积。因为我们对所有bar都计算了以自己为目标高度的最大矩阵,所以最好的结果一定会取到。但是同样,未经剪枝的还是超时。

Attention:

1. 穷举时,我们需要维护一个从当前k 向前的最小高度。

int lowest = height[i];            for(int j = i; j >= 0; j--)            {                lowest = min(height[j], lowest);
2. 注意剪枝的方法

for(int k = i + 1; k < height.size(); k++)            {                if(height[k] < height[k-1])                {                    i = k - 1;                    break;                }                else                {                    i = k;                }            }

AC Code:

class Solution {public:    int largestRectangleArea(vector<int> &height) {        int maxarea = 0;                for(int i = 0; i < height.size(); i++)        {            for(int k = i + 1; k < height.size(); k++)            {                if(height[k] < height[k-1])                {                    i = k - 1;                    break;                }                else                {                    i = k;                }            }                        int lowest = height[i];            for(int j = i; j >= 0; j--)            {                lowest = min(height[j], lowest);                int curarea = lowest * (i - j + 1);                maxarea = max(maxarea, curarea);            }        }        return maxarea;    }};

Answer 2: 栈 优化算法

思路:我们维护一个栈,这个栈从低向上的高度依次是递增的,如果遇到当前bar的高度比栈顶元素低,那么就出栈直到满足条件,这个过程中,我们不断把出栈的栈顶元素当做最低高度计算最大面积。关键问题在于出栈时,如何确定出栈元素所对应的高度的最大范围是多少。如果栈为空,那么说明到目前为止的所有元素(当前下标元素除外)都比出栈元素高度要大(否则栈内还会有元素),那么矩阵面积就是栈顶元素高度h[t] * 当前下标i . 如果栈不为空,那么就是从当前栈顶元素的下一个到当前下标元素之前都比出栈元素高度要大,因为当前栈顶元素是第一个比出栈元素小的。具体可以看下这幅图:

另外一个细节需要注意的是,弹栈过程中面积的计算。

h[t] * (stack.isEmpty() ? i : i - stack.peek() - 1)

h[t]是刚刚弹出的栈顶端元素。此时的面积计算是h[t]和前面的“上流社会”能围成的最大面积。这时候要注意哦,栈内索引指向的元素都是比h[t]小的,如果h[t]是目前最小的,那么栈内就是空哦。而在目前栈顶元素和h[t]之间(不包括h[t]和栈顶元素),都是大于他们两者的。

我们需要注意的是,最后要对剩下的栈做清空并判断,因为算法每次是对于前面的元素面积进行判断,如果循环结束后如果栈内仍然有元素,还是要继续维护面积直到栈为空。

AC Code:

class Solution {public:    int largestRectangleArea(vector<int> &height) {                stack<int> stk;        int maxarea = 0;        int tp;   //栈顶元素        int area_with_tp;  //存储以栈顶元素作为最短板的面积                int i = 0;        while(i < height.size())        {            if(stk.empty() || height[i] >= height[stk.top()])                stk.push(i++);            else            {                tp = stk.top();                stk.pop();                area_with_tp = height[tp] * (stk.empty() ? i : i - stk.top() - 1);                maxarea = max(maxarea, area_with_tp);            }        }                //如果栈仍然非空 继续处理        while(!stk.empty())        {            tp = stk.top();            stk.pop();            area_with_tp = height[tp] * (stk.empty() ? i : i - stk.top() - 1);            maxarea = max(maxarea, area_with_tp);        }        return maxarea;    }};

这道题有两篇博文,可以帮助理解。

Largest Rectangle in Histogram

Largest Rectangular Area in a Histogram | Set 2

这道题比较绕,也比较难理解,需要仔细想想。优化的方法只需要扫描一遍,时间复杂度是O(N)、空间复杂度是栈的大小,最坏是O(N)。

这道题还有个扩展题目 Maximal Rectangle, 利用这道题作为子程序,是一道比较复杂的题目。

0 0