Stacks & Queues · 17 of 38
Largest rectangular Area in Histogram
Find the biggest rectangle of floor tiles you can lay flat across a row of towers of different heights.
- Simple way
- time O(n^2)
room O(1) - Clever way
- time O(n)
room O(n)
The problem, simply
You get a row of bars standing side by side. Every bar is 1 wide, and heights[i] says how tall bar i is. Draw one rectangle that sits on the floor and stays inside the bars. Give back the largest area such a rectangle can have.
A rectangle that covers several bars can only be as tall as the shortest bar it covers.
A story to remember it
Picture it
Six bars of width 1. The shaded block over bars 2 and 3 is 5 tall and 2 wide, so its area is 10. No other block is bigger.
- answer
Examples
The classic
- In
heights = [2, 1, 5, 6, 2, 3]- Out
10
Bars 5 and 6 together hold a rectangle 5 tall and 2 wide.
A wide low rectangle wins
- In
heights = [6, 2, 5, 4, 5, 1, 6]- Out
12
Bars 5, 4 and 5 hold a rectangle 4 tall and 3 wide. The tall 6s alone only give 6.
Stairs going up
- In
heights = [1, 2, 3, 4, 5]- Out
9
Height 3 across the last three bars gives 9. Height 2 across four bars gives 8, and height 5 alone gives 5.
All the same
- In
heights = [3, 3, 3]- Out
9
The whole row is one rectangle, 3 tall and 3 wide.
One bar or none
- In
heights = [7] and heights = []- Out
7 and 0
One bar is its own rectangle. No bars means area 0.
Way 1: the simple way
Try every stretch of bars. Start at bar i, then walk right with j. Keep the shortest height seen between i and j. The rectangle over that stretch has area shortest * (j - i + 1).
- For each start
i, setlow = heights[i]. - For each end
jfromito the last bar, updatelow = min(low, heights[j]). - Area is
low * (j - i + 1). Keep the biggest.
Way 1 starting at bar 2: stretch right one bar at a time and keep the shortest height seen. With bars 2 and 3 the shortest is 5, so area 5 x 2 = 10.
- path
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int best = 0;
for (int i = 0; i < n; i++) {
int low = heights[i];
for (int j = i; j < n; j++) {
low = Math.min(low, heights[j]); // the banner can only be this tall
best = Math.max(best, low * (j - i + 1));
}
}
return best;
}
}How long it takes: about n * n / 2 stretches, O(n^2). Extra room: a few numbers, O(1). Too slow when there are 100,000 bars.
Way 2: the clever way
Each bar wants to know two things: the nearest shorter bar on its left and the nearest shorter bar on its right. Its banner fills the space between them.
Keep a stack of bar positions whose heights go up from bottom to top. Walk left to right.
- Look at bar
iwith heighth. While the bar on top of the stack is taller thanh, that top bar has found its right wall: bari. Pop it. - Its left wall is the bar now on top of the stack (the stack is sorted, so that bar is shorter). If the stack is empty, it can reach all the way to the start.
- Width is
i - left - 1, oriif the stack is empty. Area isheight * width. Keep the biggest. - Push
i. - At the end, pretend there is one more bar of height 0. It pops everything that is left.
The stack finds where each bar must stop
01 / 15
Bars 2, 1, 5, 6, 2, 3. The stack will hold bars whose right edge we do not know yet. They always grow taller from bottom to top.
- best
- 0
- looking now
- checking
- answer
- path
- just added
import java.util.*;
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
Deque<Integer> stack = new ArrayDeque<>(); // bar positions, heights going up
int best = 0;
for (int i = 0; i <= n; i++) {
int h = (i == n) ? 0 : heights[i]; // a pretend bar of height 0 at the end
while (!stack.isEmpty() && h < heights[stack.peek()]) {
int tall = heights[stack.pop()]; // this bar just found its right wall
int width = stack.isEmpty() ? i : i - stack.peek() - 1;
best = Math.max(best, tall * width);
}
stack.push(i);
}
return best;
}
}How long it takes: every bar is pushed once and popped once, so the whole walk is O(n). Extra room: the stack can hold every bar when the heights only go up, O(n).
Watch out for
- Forgetting the pretend 0 bar at the end. Bars still on the stack never get measured, and stairs going up return the wrong answer.
- Using
<=instead of<when popping. Both give the right answer for equal heights, because the last equal bar still measures the full width. Pick one and be ready to explain why. - Area can overflow
intif heights andnare both huge. Uselongforbestif the limits allow it.
What interviewers ask next
- Maximal rectangle of 1s in a 0 and 1 grid. Go row by row and treat each column as a bar whose height is the number of 1s stacked above. Run this histogram trick on every row.
O(rows * cols). - Can you do it with two passes instead? Yes. One pass finds the nearest shorter bar on the left for every bar, another finds it on the right, then
area = h * (right - left - 1). SameO(n). - Trapping rain water looks similar. It uses the tallest bar on each side instead of the nearest shorter one, and can be done with two pointers and
O(1)room. - Sum of the minimum of every subarray. The same "how far can this bar stretch while it is the smallest" idea counts how many subarrays have each bar as their minimum.
Remember this
Grown-up words: the towers are a histogram, the pile of rising bars is a monotonic increasing stack, the walls are the previous smaller element and the next smaller element, and the pretend 0 bar is a sentinel.