题目描述:
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.
能想到的思路:
首先是O(n^2)的解法,也就是逐个判断当前的bar能够向左右延伸到什么位置为止,然后用bar的高度乘以延伸的宽度,并判断是否要更新最大值。
但这个复杂度是过不了大数据的。思考了很久也没有找到解决办法,因此参考了别人的解决方法。
思路:我们可以从左到右遍历所有bar,并将其push到一个stack中,如果当前bar的高度小于栈顶bar,我们pop出栈顶的bar,同时以该bar计算矩形面积。那么我们如何知道该bar的最左索引ln和最右索引rn呢?rn铁定就是当前遍历到的bar的索引,而ln则是当前的栈顶bar的索引,因为此时栈顶bar的高度一定小于pop出来的bar的高度,而栈中的bar的高度是递增的。
还有一个理解方式是:
如下图所示,从左到右处理直方,i=4时,小于当前栈顶(及直方3),于是在统计完区间[2,3]的最大值以后,消除掉黑色部分,然后把红色虚线部分作为一个大直方插入。因为,无论后面还是前面的直方,都不可能得到比目前栈顶元素更高的高度了。
这就意味着,可以维护一个递增的栈,每次比较栈顶与当前元素。如果当前元素小于栈顶元素,则入站,否则合并现有栈,直至栈顶元素小于当前元素。结尾入站元素0,重复合并一次。
上面的两个方法分别对应这两种实现方式。第一种是以index作为元素push到stack中,用index来求得矩形的宽度。在这里有一个难点,考虑例子{3,5,6,4,4},因为到第一个4的时候5和6都被pop出栈了,到第二个4的时候栈内元素为{3,4}对应的下标即{0,3}。计算宽度的时候,不能用栈顶元素的下标来计算宽度,而应该使用栈顶元素的下一个元素来进行计算,并且也要考虑到若栈内只有栈顶元素一个元素的情况。
第二种实现方式就是用height[index]的值放入stack中。这种情况下,需要将前面元素的值阶段成最右元素的值,实现起来操作更多一些,可以用stack的size来计算矩形的宽。这里就实现前一种方法了。
无论哪种方式,都要考虑到最后一个元素入栈后的情况。为了让程序更简洁,在height尾部放置一个最小值(如0),使得程序总是能够求取最后一个矩阵的大小。
代码如下:
class Solution {
public:
int largestRectangleArea(vector<int>& height) {
if(height.size() == 0)
return 0;
//put a minimum number to calculate the area of last rectangle
height.push_back(0);
stack<int> h;
int result(0), index(0), top(0);
while(index < height.size()) {
if(h.empty() || height[h.top()] < height[index]) {
h.push(index++);
}
else {
top = h.top();
h.pop();
//if stack had only 1 element, use index as width, else use current top index to calculate width
top = h.empty() ? height[top] * index : height[top] * (index - h.top() - 1);
result = result > top ? result : top;
}
}
height.pop_back();
return result;
}
};