给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
leetcode
解题思路:
- 首先想暴力该怎么做?
就是依次遍历数组,求以每一个柱子为高度的最大面积,当遍历到一个元素的时候,在去找到它的左右两边第一个比它小的柱子的位置,这样就能取最大值。暴力的方法是N方的。 - 降低时间复杂度的方法。因为每次需要去遍历每个元素左右两边第一个比它小的位置,就很费时间。所以,可以先通过两次遍历,分别求每个元素在左右两个方向上,第一个比他小的元素的索引值,这样,就不需要每次都去重新找了。如果这个数组在一个方向上就是最小值,那么下标值就用-1或者数组的长度来代替计算。
- 通过单调栈的方法,就能通过一次遍历,寻找一个队列中,每个元素,在一个方向上的第一个比其小或者大的元素了。
- 最后,一次遍历数组,每次用之前存下来的左右两边第一个比它小的元素的下标之差,然后乘以其高度,就是以当前元素为高度的最大值,然后依次比较就是答案。
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
// 利用两个数组,存储每个元素左右两边第一个比它小的元素的下标
int[] l = new int[n], r = new int[n];
Deque<Integer> stack = new LinkedList<>();
int res = 0;
for(int i = 0; i < n; i++) {
// 如果栈顶元素比它大,就不断弹出,因为在之前的比它大的元素已经不会被用到了
while(!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
stack.pop();
}
// 弹到最后剩下的,就是第一个比它小的元素了
l[i] = stack.isEmpty() ? -1 : stack.peek();
stack.push(i);
}
stack = new LinkedList<>();
for(int i = n - 1; i >= 0; i--) {
while(!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
stack.pop();
}
r[i] = stack.isEmpty() ? n : stack.peek();
stack.push(i);
}
for(int i = 0; i < n; i++) {
res = Math.max(res, heights[i] * (r[i] - l[i] - 1));
}
return res;
}
}