题目
Given an array of integers heights representing the histogram's bar height where the width of each bar is 1, return the area of the largest rectangle in the histogram.
Input: heights = [2,1,5,6,2,3]
Output: 10
Explanation: The above is a histogram where width of each bar is 1.
The largest rectangle is shown in the red area, which has an area = 10 units.
Constraints:
1 <= heights.length <= 1050 <= heights[i] <= 104
解答
- intuitive thoughts 对于最佳情况,即最大长方形而言,它一定有一个最矮的bar i,作为它的高度,左右两个边界的距离作为它的长度。左边界一定比左边界左一格的bar高,右边界一定比右边界右一格的bar高(若不满足,则这个就不是最大的长方形了,它还能向外扩展)。
那么我可以对任意一个bar i,假设以它作为最矮的那个,找到它的左右边界,得到一个area,遍历整个height数组,比较这些area获取最大值 ==> O(N2)
- 通过单调栈(monotonic stack)进行优化 达到O(N) 单调栈:即栈内元素大小从栈底到栈顶是由小到大,若遇到一个新的元素小于栈顶元素,则pop()栈顶元素,直到栈顶元素小于这个新的元素或栈为空,再add这个元素。
具体实现: 我们考虑相邻两个bar i和bar i+1,若heights[i] > heights[i+1],那么以i作为最矮的那个(即rectangle的高度)的长方形的右边界就是他本身,而左边界是向左看第一个比它矮的右边一格(也就是单调栈内它的前一个元素idx+1)。
若heights[i] <= heights[i+1],那么以i作为最矮的那个的长方形的右边界是向右看第一个递减bar的左边一格,左边界和上述一致。
因此,根据heights数组维护一个单调栈,当遇到heights[i+1] < heights[i]时,pop()出栈内大于它的元素,而每次pop()都能找到以i作为最矮的那个的长方形的面积,囊括了所有的情况。
class Solution {
public int largestRectangleArea(int[] heights) {
int max = 0;
int n = heights.length;
Stack<Integer> monotonicStack = new Stack<>();
for (int i = 0; i <= n; i++) {
int curHeight = i == n ? 0 :heights[i];
while (!monotonicStack.isEmpty() && curHeight < heights[monotonicStack.peek()]) {
//遇到了一个下降
int peekIdx = monotonicStack.pop();
int preMaxHeight = heights[peekIdx];
int width = monotonicStack.isEmpty()? i : i - monotonicStack.peek() -1;
max = Math.max(max, preMaxHeight * width);
}
monotonicStack.add(i);
}
return max;
}
}