题目链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
题目描述
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
思路
1 暴力
将i
位置作为左边界,j
遍历i~n
得到(i,j)
这个区间的最小高度,(j-i+1)*minHeight
得到以i
作为左端点,j
作为右端点的最大矩形面积。
复杂度分析
时间复杂度:
。 需要枚举所有可能的柱子对。
空间复杂度:
。不需要额外的空间。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
if (heights.empty()) return 0;
int maxArea = 0;
for (int i = 0; i < heights.size(); ++i) {
int minHeight = heights[i];
for (int j = i; j < heights.size() && heights[j]!=0; ++j){
minHeight = min(minHeight, heights[j]);
maxArea = max(maxArea,minHeight*(j-i+1));
}
}
return maxArea;
}
};
很遗憾,超时了=。=!
2 栈
在这种方法中,我们维护一个栈。一开始,我们把 -1
放进栈的顶部来表示开始。初始化时,按照从左到右的顺序,我们不断将柱子的序号放进栈中,直到遇到相邻柱子呈下降关系,也就是 a[i-1] > a[i]a[i−1]>a[i]
。现在,我们开始将栈中的序号弹出,直到遇到 stack[j]
满足a[stack[j]]≤a[i]
。每次我们弹出下标时,我们用弹出元素作为高形成的最大面积矩形的宽是当前元素与 stack[top-1]
之间的那些柱子。也就是当我们弹出 stack[top]
时,记当前元素在原数组中的下标为 i
,当前弹出元素为高的最大矩形面积为:
(i−stack[top−1]−1)×a[stack[top]]
.
更进一步,当我们到达数组的尾部时,我们将栈中剩余元素全部弹出栈。在弹出每一个元素是,我们用下面的式子来求面积: (stack[top]−stack[top−1])×a[stack[top]]
,其中,stack[top]
表示刚刚被弹出的元素。因此,我们可以通过每次比较新计算的矩形面积来获得最大的矩形面积。
复杂度分析
时间复杂度:
。 n个数字每个会被压栈弹栈各一次。
空间复杂度:
。用来存放栈中元素。
/*
* 单调栈
* 时间复杂度O(n) 空间复杂度O(n)
*/
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
if (heights.empty()) return 0;
stack<int> s; // 存储序号
s.push(-1);
int maxArea = 0;
for (int i = 0; i < heights.size(); ++i) {
// 下降时pop
while (s.top() != -1 && heights[s.top()] >= heights[i]){
int tmp = s.top();
s.pop();
// 用弹出元素作为高形成的最大面积矩形,其宽是当前元素与s[top-1]之间的那些柱子
maxArea = max(maxArea, heights[tmp] * (i-s.top() - 1));
}
s.push(i);
}
while (s.top()!= -1){
int tmp = s.top();
s.pop();
int curArea = heights[tmp] * (heights.size() - s.top() - 1);
maxArea = max(maxArea, curArea);
}
return maxArea;
}
};