Largest Rectangle in a Histogram
Pattern: Monotonic Stack · Difficulty: Hard · Asked at: Amazon, Google, Microsoft
Classic version: LeetCode 84 · LeetCode 85
Problem
heights[i] is the height of a histogram bar of width 1. Return the area of the largest rectangle that fits entirely under the histogram.
Examples
largest_rectangle([2, 1, 5, 6, 2, 3]) → 10 # bars 5 and 6, height 5, width 2
largest_rectangle([2, 4]) → 4
Starter code
def largest_rectangle(heights: list[int]) -> int:
pass
Hints
Hint 1
For bar i as the shortest bar of the rectangle, the rectangle extends to the nearest shorter bar on each side.
Hint 2
Keep an increasing stack of indices. When a shorter bar arrives, the popped bar’s right limit is the current index and its left limit is the new stack top.
Hint 3
Append a sentinel bar of height 0 to flush the stack at the end.
Where this shows up in data engineering
A classic “hard” that tests whether you truly understand monotonic stacks rather than pattern-matching. The 2D extension (largest all-ones rectangle in a matrix) builds a histogram per row: the same “reduce a 2D problem to repeated 1D” move used in grid/heatmap aggregations.
Solution
def largest_rectangle(heights: list[int]) -> int:
stack = [] # indices of bars with increasing heights
best = 0
for i, h in enumerate(heights + [0]): # sentinel flushes everything
while stack and heights[stack[-1]] > h:
top = stack.pop()
left = stack[-1] if stack else -1 # nearest shorter bar on the left
width = i - left - 1 # i is the nearest shorter bar on the right
best = max(best, heights[top] * width)
stack.append(i)
return best
Tests
Your solution should pass these:
assert largest_rectangle([2, 1, 5, 6, 2, 3]) == 10
assert largest_rectangle([2, 4]) == 4
assert largest_rectangle([]) == 0
assert largest_rectangle([5]) == 5
assert largest_rectangle([1, 1, 1, 1]) == 4
assert largest_rectangle([6, 2, 5, 4, 5, 1, 6]) == 12
assert largest_rectangle([4, 2, 0, 3, 2, 5]) == 6
Explanation
Reframe: the optimal rectangle has some bar as its shortest; for that bar, the rectangle spans between the nearest strictly shorter bars on each side. So we need “previous smaller” and “next smaller” for every bar, which is exactly what an increasing stack produces.
Mechanics: when h arrives and is shorter than the stack top, the top’s next-smaller is i, and its previous-smaller is whatever lies below it in the stack. Compute its area and pop. The sentinel 0 at the end pops everything left.
Complexity: O(n) time, O(n) space; each index is pushed and popped once.
Follow-up questions
Largest rectangle of 1s in a binary matrix?
For each row, compute heights[c] = consecutive 1s ending at this row in column c, then run largest_rectangle on that row. O(R·C).