- 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.
Example
Given height = [2,1,5,6,2,3],
return 10.
思路:单调递增栈。
这题实际上等价于:对每个矩形求左右最近的一个比他低的矩形的边界,然后左右两侧距离相加(还要-1,因为自身算了2遍)×该矩形高度。然后找出所有矩形中该操作的最大值。
注意:
- 为什么是单调递增栈而不是单调递减栈?
因为对栈top矩形来说,我们要找左右两边最近的比他低的矩形。我们从左到右扫描,如果新的矩形比top矩形低,则新的矩形是top矩形的右边最近的比它低的元素。同时,top矩形在栈内的下面一个矩形是其左边离它最近的低的元素。 - 时间复杂度O(n)。因为每个元素入栈出栈一次。
- 注意w = s.empty() ? i : i - s.top() - 1。
这里首先要注意stack可能会empty,如果是,则直方图宽度为i。
若否,则直方图宽度为i-s.top()-1,因为直方图的右边界为i - 1,左边界为s.top()+1,所以宽度为(i-1)-(s.top()+1)+1=i-s.top()-1。
注意这里的s.top()已经更新了,它实际上是pop()掉的那个s.top()的下面一个。 - 最右边加一个dummy,确保最后一个矩形也被考虑。但要注意for循环里面是<=len,因为加了一个dummy, 实际len的值加了1。
- while循环里面用>=和>都可以,效果是等价的。
例如,nums=[5,5,5,5,5],用>=的话每个5都会挨个挨个pop掉,用>的话,所有的5是到最后一步才逐个pop掉。但效果是一样的。
代码如下:
class Solution {
public:
/**
* @param height: A list of integer
* @return: The area of largest rectangle in the histogram
*/
int largestRectangleArea(vector<int> &height) {
int len = height.size();
if (len == 0) return 0;
int maxArea = 0;
vector<int> height2 = height;
height2.push_back(-1);
stack<int> monoIncStack; // mono increasing stack
for (int i = 0; i <= len; ++i) {
while(!monoIncStack.empty() &&
(height2[monoIncStack.top()] >= height2[i])) {
int top = monoIncStack.top();
monoIncStack.pop();
int h = height2[top];
int w = monoIncStack.empty() ? i : i - monoIncStack.top() - 1;
//note it is not i - top - 1;
maxArea = max(maxArea, h * w);
}
monoIncStack.push(i);
}
return maxArea;
}
};
这题也可以在数组两边各加一个dummy,这样就不用判断stack.empty()了。这里要注意data.size()已经加了2。代码如下:
int LargestRec2(vector<int> &data) {
stack<int> monoStack; //单调递增栈
int maxV = 0;
//add two dummy boundaries
data.insert(data.begin(), -1);
data.push_back(-1);
for (int i=0; i<data.size(); ++i) {
while(!monoStack.empty() && data[monoStack.top()]>data[i]) {
int oldTop = monoStack.top();
monoStack.pop();
maxV = max(maxV, data[oldTop]*(i-monoStack.top()-1));
}
monoStack.push(i);
}
return maxV;
}