解题方法
我们要求的是在一个由数字组成的柱状图中,能够找到的最大矩形的面积。这个矩形可以是水平也可以是垂直的。
首先,我们需要知道每个柱子左右两边第一个比它矮的柱子的位置。这样我们才能确定一个柱子能构成的所有可能的矩形。
如何找到柱子两边第一个比它矮的柱子位置呢?
我们利用单调栈找到每个柱子的左边界和右边界,将其存储在数组 l
和 r
中。
维护一个严格单调递增的栈,
- 当一个柱子可以入栈时,说明栈顶元素就是就是左边第一个比它矮的柱子位置。
- 当入了栈的柱子被当前柱子排出栈时,说明当前柱子是排出栈的柱子的第一个小于等于它的柱子,也就找到了排出栈柱子的右边第一个不比它高的柱子位置(因为有可能相等)。
- 使用右边不比它高的柱子来计算答案时不一定是最大的面积,但可以保证高度相等的最右侧柱子的答案是最大的。
得到数组 l
和 r
后,我们遍历每个柱子,用它的高度乘以它左右两边第一个比它矮的柱子之间的距离,这样就能得到以当前柱子为高的所有可能的矩形的面积。
最后,我们只需要在这些面积中找到最大的一个即可。
Code
class Solution {
// 寻找每个柱子左右两边第一个比它矮的柱子的位置
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] l = new int[n], r = new int[n];
Arrays.fill(r, n);
Stack<Integer> stack = new Stack<Integer>();
for(int i = 0; i < n; i++){
// 当栈不为空,并且栈顶的柱子高度大于等于当前柱子的高度时
while(!stack.isEmpty() && heights[stack.peek()] >= heights[i]){
// 弹出栈顶元素,更新右边界
r[stack.pop()] = i;
}
// 如果栈为空,则当前柱子左边第一个比它矮的柱子是-1,否则就是栈顶元素
l[i] = stack.isEmpty() ? -1 : stack.peek();
// 把当前柱子压入栈
stack.push(i);
}
int ans = 0;
// 遍历每个柱子,计算以它为高的所有可能的矩形的面积
for(int i = 0; i < n; i++){
ans = Math.max(ans, heights[i] * (r[i] - l[i] - 1));
}
// 返回最大的矩形面积
return ans;
}
}