一.题目描述
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.
二.题目分析
看到这个题目,第一时间应该推出的是直方图中最大矩形的高度必然和某一个柱子的高度相等。
因此,容易想到遍历数组,对于某一立柱height[index]
,往左右两边扩展,看看以当前立柱的高度最多能包含多大的矩形面积,如图中第二个立柱的高度为1
,扫描其左右元素发现所有元素均大于1
,故该高度下宽度为6
,得到面积1 * 6 = 6
。不断更新得到的最大面积,最后返回该值即可。这种方法的时间复杂度为O(n^2)
,会超时。
正确而高效的方法是网上广泛讨论的一种方法,借助栈来实现算法,但是该算法并不容易马上想到。这里参考了一个简单的例子来说明此算法:
图中,height = [5,6,7,8,3]
,特点是除了最后一个,前面全部保持递增,且最后一个立柱的高度小于前面所有立柱高度。
对于这种特点的柱状图,我们知道除了最后一个,从第一个到倒数第二个立柱的高度都在升高,如果挨个使用每一个柱的高度作为矩形的高度,那么依次能得到的矩形的宽度就可以直接算出来:使用5
作为高度可以使用前四个立柱组成 4*5
的矩形,同理使用高度6
的立柱可以组成3*6
的矩形…… 因此只需要遍历一次height
,就可以计算出最大面积,也就是时间复杂度O(n)
。
参考博文中,将这种特点的柱状图称为“波峰图”。
下面介绍算法的具体步骤:
1.在height
数组的尾部添加0
,其作用是得到符合上述规律的直方图。
2.定义了一个栈k,遍历数组height
,时如果height[index]
大于stack.top()
,入栈;反之则出栈,直到栈顶元素小于height[index]
。由于出栈的这些元素高度都是递增的,我们可以依次求出这些立柱中所围成的矩形面积,并更新其最大值。
3.重复以上过程,直到遍历到最后那个值0的元素,会把栈中元素全部弹出并作最后一次面积的计算,并返回面积的最大值。
注意栈中存的不是height
元素的大小,而是height
的索引,这样做的好处是不会影响宽度的计算,当前遍历的索引值 - 当前栈顶索引值 - 1 = 当前矩形的宽度。
三.示例代码
class Solution
{
public:
int largestRectangleArea(vector<int> &height)
{
if (height.size() == 0) return 0;
height.push_back(0);
int MaxHist = 0; // 存储最大矩形面积
stack<int> k; // 使用栈存储height的索引
for (int index = 0; index < height.size(); ++index)
{
if (k.empty() || height[k.top()] < height[index])
k.push(index);
else
{
int temp = k.top();
k.pop();
// 局部面积计算,宽度为当前index与栈顶存储的索引k.top()的距离
int localArea = height[temp] * (k.empty() ? index : (index - k.top() - 1));
if (localArea > MaxHist)
MaxHist = localArea;
--index;
}
}
return MaxHist;
}
};
四.小结
该题目要求遍历每一个立柱并将其视为矩形高度,求出直方图中能构成矩形的最大面积,但是它通过巧妙地使用栈,把整个height变成一组组“波峰图”来求解,做到了O(n)的时间复杂度,值得深入学习!
参考链接:
http://www.cnblogs.com/felixfang/p/3676193.html
http://www.cnblogs.com/avril/archive/2013/08/24/3278873.html
版权声明:本文为博主原创文章,未经博主允许不得转载。