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.
For example,
Given heights = [2,1,5,6,2,3],
return 10.
思路
对于一个bar x,计算以x为最低点的面积最大的矩形,把全部bar都计算一遍,就可以找到柱状图中面积最大的矩形。
如何找到以x为最低点的矩形?我们需要知道x左右两侧,第一个比x低的bar的位置,分别记做left index和right index。
从左至右遍历所有的bar,用栈来维护这些bar。保证栈中的bar是递增,即新遇到的bar比栈顶元素低的时候,就弹出栈顶元素。当一个bar弹出栈的时候,这个bar就是x,新遇到的bar的坐标就是right index,栈中上一个元素坐标就是left index:
- 创建一个空栈
- 从第一个bar开始扫描
- 如果栈空或者
height[i] >= 栈顶元素高度
,则将i(下标)
压入栈中 - 如果
height[i] < 栈顶高度
,不断弹出栈顶元素,直到height[i] >= 栈顶元素高度或栈空
。- 令弹出栈的的元素高度是height[tp],计算以height[tp]为最低点的矩形面积。
- 对于height[tp]这个bar,left index是栈中前一个元素,right index是i。
- 由于每个Bar入栈出栈各一次,因此总时间复杂度为O(N)。
具体实现时,再尾部加入height = 0的bar,确保之前所有bar都能出栈
class Solution {
public int largestRectangleArea(int[] heights) {
if (heights == null || heights.length == 0) return 0;
Stack<Integer> stack = new Stack<Integer>();
List<Integer> newHeights = new ArrayList<Integer>(heights.length);
for (int i = 0; i < heights.length; i++) {
newHeights.add(Integer.valueOf(heights[i]));
}
newHeights.add(0);
int start = 0;
int end = newHeights.size();
int maxArea = 0;
for(int i = 0; i < end; i++) {
int rightIndex = 0;
int leftIndex = 0;
while (!stack.isEmpty() && newHeights.get(stack.peek()) >= newHeights.get(i)) {
int tempHeight = stack.peek();
stack.pop();
rightIndex = i;
leftIndex = stack.isEmpty() ? -1 : stack.peek();
maxArea = Math.max(maxArea, (rightIndex - leftIndex - 1) * newHeights.get(tempHeight));
}
stack.push(i);
}
return maxArea;
}
}