84. 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:
Input: [2,1,5,6,2,3]
Output: 10
方法1: stack
思路:
主要破题点在于,对于某一个位置的楼,我们要找以它为顶点的长方形,只需要知道它左边的低点(相对自己)和右边的低点,这个范围是能取到的最大长度。同时要注意,再往左边的低点也需要依次保留,以计算高度虽然更低,但长度更宽的长方形。那么如何在一次遍历中追溯两个低点?还要依次记录前序所有低点?这就用到了stack。具体操作如下:
- 如果当前点高于前点,或者前点不存在,可以推入栈(因此我们保证了栈内严格递增)。
- 如果当前点低于了当前栈顶(注意不是index上的前点),那说明它已经成为了之前某些高度的右低点,对于这些长方形,已经可以开始计算。
- 具体是哪些长方形?以栈内第一个元素为height,第二个元素为左低点的长方形。而这样的长方形不止一个,对于栈内的所有元素,只要作为左低点比当前右低点还高,就还没有限制住左边的最远位置,需要继续查找。如果pop出来的左低点已经比右低点还低,右低点成为了限制因素,可以继续往前搜。
- 所以什么时候才update一下max area?一定是等到最有可能update的时候才update一下。也就是说,当没有出现左边的更低的时候,且我们已知中间没有再低的点,那么机制目前的限制因素都是right。但我们着急update吗?还没到时候,直到遇到左低点已经比右低点还低,我们才能确定以右地点为高度的长方形到头了,再往左边只能是left说了算。而这些left说了算的rectangle,什么时候被计算了????
- 当遍历到最后一个元素,需要开始最后一轮计算。此时处理的是“以0为右低点”,也就是以最右点为右届的所有长方行面积,需要将栈pop清空,此间的长方形每一个都有可能更新最大面积。
易错点
- 栈内存的是index
- 处理空栈情况
- 最好不要用for loop,除非里面套一个while loop。弹栈的动作是一个持续过程,直到新的左低点比当前右低点更低while loop可以很好的解决这个问题。
Complexity
Time complexity: O(n)
Space complexity: O(n)
class Solution1 {
public:
// 方法1:
int largestRectangleArea1(vector<int>& heights) {
stack<int> myStack;
int maxArea = 0;
int area = 0;
int i = 0; // position the current index in the histogram
while (i < heights.size()){
// for (i = 0; i < heights.size(); i++){
// note myStack store the index, not the actual value
// heights[use myStack.top()]
if (myStack.empty() || heights[myStack.top()] <= heights[i] ){
// If stack is empty or value at index of stack is less than or equal to value at current index, push this into stack.
myStack.push(i++);
}
else {
// else the current index position start to decrease, potential change of maxArea
int top = myStack.top();
myStack.pop();
if (myStack.empty()){
// here since myStack is empty, don't need to mind the left shortest one, the width of rectangle has height = myStack.top() is equal to (i - 1 + 1) * 2
area = heights[top] * i;
}
else {
// height * width
area = heights[top] * (i - myStack.top() - 1);
}
if ( area > maxArea) {
maxArea = area;
}
}
}
while (!myStack.empty()){
int top = myStack.top();
myStack.pop();
if (myStack.empty()){
area = heights[top] * i;
}
else {
area = heights[top] * (i - myStack.top() - 1);
}
if (area > maxArea) {
maxArea = area;
}
}
return maxArea;
}
二刷:
class Solution {
public:
// 方法1:
int largestRectangleArea(vector<int>& heights) {
stack<int> st;
int i = 0, maxArea = 0, area = 0, n = heights.size();
while (i < n) {
if (st.empty() || heights[st.top()] < heights[i]) {
st.push(i++);
}
else {
int h = heights[st.top()];
st.pop();
if (st.empty()) area = i * h;
else {
area = (i - st.top() - 1) * h;
}
if (area > maxArea) maxArea = area;
}
}
while (!st.empty()) {
int h = heights[st.top()];
st.pop();
if (st.empty()) area = i * h;
else {
area = (i - st.top() - 1) * h;
}
if (area > maxArea) maxArea = area;
}
return maxArea;
}
};
方法2:
思路:
遍历右端点,在内循环遍历左端点。用到了小优化:如果右点比右边的点还低,那么可以跳过,因为更右边一定存在更大的长方形。
Complexity
Time complexity: O(n^2)
Space complexity: O(1)
// 方法2: 非最优解
int largestRectangleArea(vector<int>& heights) {
if (heights.size() == 0) return 0;
int maxArea = 0;
for (int cur = 0; cur < heights.size(); cur++){
int minHeight = heights[cur];
for (int idx = cur; idx >= 0; idx--){
minHeight = min(minHeight, heights[idx]);
maxArea = max(maxArea, minHeight * (cur - idx + 1));
}
}
return maxArea;
}
};