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.
Example:
Input: [2,1,5,6,2,3]
Output: 10
The height of a rectangle is determined by the lowest bar inside of it. So
the core idea is, for each bar, assume it is the lowest bar and see how
far it can expand. Then we have len(heights) rectangles.
Return the max area.
For a bar b whose height is h, find the closest
bar b1 on the left that is lower than h, and
b2 on the right. The area of the rectangle is
h * (i2 - i1 - 1).
Notice that if we just loop the bars from left to right,
b1 and b2 of each bar may overlap.
| index | height | width | area |
|---|---|---|---|
i
|
heights[i]
|
i2 - i1 - 1
|
height * width
|
| 0 | 2 | 1 - -1 - 1 | 2 |
| 1 | 1 | 6 - -1 - 1 | 6 |
| 2 | 5 | 4 - 1 - 1 | 10 |
| 3 | 6 | 4 - 2 - 1 | 6 |
| 4 | 2 | 6 - 1 - 1 | 8 |
| 5 | 3 | 6 - 4 - 1 | 3 |
Observe how i1 and i2 changes depending on the
height.
To reduce O(n^2) to O(n), we use a stack to store
incremental bs. Because b1 and
b2 are both lower than b, whenever we reach a
bar that is lower than the top of the stack, we know it’s a
b2. So stack top is a b. Second top is a
b1. Keep popping the b to calculate areas until
b2 is no longer lower than stack top.
/**
* @param {number[]} heights
* @return {number}
*/
var largestRectangleArea = function(heights) {
const stack = [-1]
let max = 0
for (let i2 = 0; i2 <= heights.length; i2++) {
while ((heights[i2] || 0) < heights[stack[stack.length-1]]) {
const i = stack.pop()
const i1 = stack[stack.length-1]
max = Math.max(max, heights[i] * (i2 - i1 - 1))
}
stack.push(i2)
}
return max
};
Template generated via Leetmark.