Algorithm

Largest Rectangle in Histogram

Monotonic Stack Pattern

Largest Rectangle in Histogram

Given an array of integers heights representing the histogram's bar heights where the width of each bar is 1, return the area of the largest rectangle in the histogram.

CONSTRAINTS
  • 1 <= heights.length <= 10⁵
  • 0 <= heights[i] <= 10⁴
EXAMPLE 1
Input: heights = [2,1,5,6,2,3]
Output: 10
Bars at index 2 and 3 (heights 5, 6) form a 5x2=10 rectangle.
EXAMPLE 2
Input: heights = [4, 2, 0, 3, 2, 5]
Output: 6
Bars at indices 3, 4, 5 can form a 2x3=6 rectangle.
What is the purpose of the 0 sentinel?
It ensures that after the loop finishes, any remaining bars in the stack (bars that never found a smaller neighbor to their right) are finally popped and their areas are calculated.

Any rectangle you draw inside the histogram is capped by its shortest bar — its height can't exceed the smallest bar it spans. That suggests turning the question inside out: for each bar, ask what's the widest rectangle in which this bar is the shortest one? Such a rectangle stretches left until it hits a strictly shorter bar, and right until it hits a strictly shorter bar; between those two walls, this bar's height holds all the way across. Its area is height × (right_wall − left_wall − 1). The answer is the best of these over every bar.

The brute force finds each bar's walls by scanning outward from it, which is O(N²):

python
max_area = 0
n = len(heights)
for i in range(n):
    min_h = heights[i]
    for j in range(i, n):
        min_h = min(min_h, heights[j])
        max_area = max(max_area, min_h * (j - i + 1))
return max_area

The rescan is the waste, and it has a fixable shape: what we really need is, for every bar, the nearest shorter bar on each side — a "nearest smaller neighbor" query. That's the signature of a monotonic stack: a plain push/pop stack whose contents we deliberately keep sorted, so the geometry falls out in one pass.

Keep on the stack the indices of bars whose right wall we haven't found yet, and keep their heights increasing from bottom to top. Walk left to right. When the current bar is shorter than the bar on top of the stack, the current bar is that top bar's right wall — so we can finalize the top bar now: pop it, its height is heights[popped], and its left wall is whatever index is now on top (guaranteed to be the nearest shorter bar to its left, precisely because the stack rises). The width is current − new_top − 1. Keep popping while the current bar undercuts the new top — one short bar can close out a whole run of taller bars stacked above it — then push the current index.

Two sentinels keep the edges clean: seed the stack with a virtual index -1 as a permanent left wall, and append a height-0 bar at the end so every real bar still on the stack gets forced off and measured before we finish.

python
# Monotonic Stack (O(N) Time, O(N) Space)
heights.append(0)          # sentinel to flush every remaining bar
stack = [-1]               # sentinel left wall
max_area = 0

for i in range(len(heights)):
    while len(stack) > 1 and heights[i] < heights[stack[-1]]:
        h = heights[stack.pop()]     # this bar's right wall is bar i
        w = i - stack[-1] - 1        # left wall is the new top of the stack
        max_area = max(max_area, h * w)
    stack.append(i)

return max_area

Every bar is pushed once and popped once, so the nested-looking loop is still a single linear scan.

Worked Example:[2, 1, 5, 6, 2, 3] (plus 0 sentinel)
- idx 0 (h=2) → push. Stack: [-1, 0]
- idx 1 (h=1) → 1 < 2, pop 0: width 1-(-1)-1 = 1, area 2; push 1. Stack: [-1, 1]
- idx 2, 3 (h=5, 6) → rising, push both. Stack: [-1, 1, 2, 3]
- idx 4 (h=2) → 2 < 6, pop 3: width 4-2-1 = 1, area 6. Still 2 < 5, pop 2: width 4-1-1 = 2, area 10; push 4.
- Best area seen anywhere: 10 (the 5-and-6 pair, height 5 across width 2).
Interactive Strategy Visualization
RECTILINEAR GEOMETRY ENGINE

Monotonic Stack boundary technique

2
1
5
6
2
3

Mental Model

  • The Limiter: Each bar `i` extends as long as neighboring bars are *taller*.
  • Boundary Finding: Use a Monotonic Stack to find the nearest smaller element on both sides in O(N).
LOGICSTEP 1/8
For each bar, find the largest rectangle where it is the minimum height.
HINT

O(N) Complexity

The brute force approach takes O(N²). Monotonic Stack allows us to find the best boundaries for every single bar in linear time!

O(N²) Brute Force
O(N) Pre-calculation
O(N) Monotonic Stack