Stacks and Queues · Stacks and Queues Fundamentals

Monotonic Stack Area Computation

Using previous-smaller and next-smaller boundaries (found via a monotonic stack) to know, for each bar in a histogram, exactly how wide a rectangle at that bar's height could extend before hitting something shorter.

  • 5 min read
  • 8 practice questions
  • 2 graded problems
On this page
  1. Description
  2. The approach
  3. A second flavor: a matrix of 1s as stacked histograms
  4. Where you'll see it
  5. Which tool for which job?
  6. Common mistakes
  7. Check yourself
  8. Key takeaways
  9. Quick revise
  10. Practice

Description

Bars of width 1 stand side by side; what's the largest rectangle that fits under them? Trying every pair of edges is O(n^2). Every candidate rectangle, though, is as tall as its shortest bar - so for each bar, you only need the widest stretch around it where it is the shortest: from the nearest shorter bar on its left to the nearest shorter bar on its right.

This skill covers finding each bar's nearest shorter neighbors with one increasing stack, measuring its rectangle when it's popped, and flushing the stack with a final zero-height bar. It also covers turning a binary matrix into one histogram per row.

We'll go from simple to more technical:

  1. The pattern: Largest Rectangle in Histogram with an increasing stack of indices.
  2. A second flavor: Maximal Rectangle, a matrix of 1s as stacked histograms.
  3. Where it shows up (free space in occupancy grids, layout, image masks).
  4. What breaks it: no final flush, the width formula, overflow, the matrix reset.

The approach

Java

int largestRectangleArea(int[] heights) {
    int n = heights.length, best = 0;
    Deque<Integer> stack = new ArrayDeque<>();          // indices, heights increasing bottom to top
    for (int i = 0; i <= n; i++) {
        int cur = (i == n) ? 0 : heights[i];            // a final 0 flushes every remaining bar
        while (!stack.isEmpty() && heights[stack.peek()] >= cur) {
            int height = heights[stack.pop()];
            int width = stack.isEmpty() ? i : i - stack.peek() - 1;   // between the two shorter bars
            best = Math.max(best, height * width);
        }
        stack.push(i);
    }
    return best;
}

Python

def largest_rectangle_area(heights: list[int]) -> int:
    n, best = len(heights), 0
    stack = []                                    # indices, heights increasing bottom to top
    for i in range(n + 1):
        cur = 0 if i == n else heights[i]         # a final 0 flushes every remaining bar
        while stack and heights[stack[-1]] >= cur:
            height = heights[stack.pop()]
            width = i if not stack else i - stack[-1] - 1   # between the two shorter bars
            best = max(best, height * width)
        stack.append(i)
    return best

When bar i is shorter than the top of the stack, the popped bar has found its right boundary (i); its left boundary is the bar now exposed on the stack (or the array's start if the stack is empty). Its rectangle is height x (i - left - 1). The imaginary bar of height 0 at position n pops everything still waiting - without it, an increasing histogram such as [1, 2, 3, 4, 5] never pops and returns 0 instead of 9. Heights up to 10^4 and n up to 10^5 keep areas within an int; with heights up to 10^9, compute in long (Python's ints don't overflow).

A second flavor: a matrix of 1s as stacked histograms

The largest rectangle of 1s in a binary matrix: for each row, let heights[j] be the number of consecutive 1s ending at that row in column j - reset to 0 at a 0. Each row is then a histogram, and the answer is the best histogram area over all rows:

Java

int maximalRectangle(int[][] grid) {
    int[] heights = new int[grid[0].length];
    int best = 0;
    for (int[] row : grid) {
        for (int j = 0; j < row.length; j++) heights[j] = row[j] == 1 ? heights[j] + 1 : 0;
        best = Math.max(best, largestRectangleArea(heights));
    }
    return best;
}

Python

def maximal_rectangle(grid: list[list[int]]) -> int:
    heights = [0] * len(grid[0])
    best = 0
    for row in grid:
        heights = [h + 1 if cell == 1 else 0 for h, cell in zip(heights, row)]
        best = max(best, largest_rectangle_area(heights))
    return best

That's O(rows x cols). Forgetting the reset (keeping the old height at a 0) builds towers over gaps and overstates the area.

Where you'll see it

Finding the largest free rectangle in an occupancy grid (placing a window or widget on a screen, floor-plan layout, finding empty regions in an image mask) is the matrix version. Profile "skylines" in computational geometry use the same nearest-shorter-bar boundaries.

Which tool for which job?

You needUse
The largest rectangle under a histograman increasing stack, popped by shorter bars
The largest rectangle of 1s in a matrixper-row heights, then the histogram answer
The largest square of 1sa DP: min of up, left and diagonal, plus 1
The number of all-1 rectanglesper-row heights and a stack of running counts
Water trapped between barsa stack of layers, or two pointers

Common mistakes

MistakeWhat happensDo this instead
No final height-0 bar[1, 2, 3, 4, 5] returns 0 instead of 9flush with a 0 at index n
Width from the popped indexrectangles come out too narrowi - newTop - 1, or i when the stack is empty
height x width in an int100,000 bars of 10^9 gave 2147447808multiply in long
No reset at a 0 celltowers over gaps overstate the areaheights[j] = 0 at a 0
Expanding from every bar49,995,000 steps for 10,000 sorted barsthe stack, O(n)

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. When a bar is popped, what are its left and right boundaries?

Show answer

Right: the current index i, the first bar to its right that is shorter. Left: the bar now on top of the stack (the nearest shorter bar to its left), or -1 (the start) if the stack is empty. Its width is the gap between them: i - left - 1.

2. What goes wrong without the height-0 bar at the end?

Show answer

Bars that never meet a shorter bar to their right are never popped, so their rectangles are never measured. For [1, 2, 3, 4, 5] nothing is ever popped and the answer comes out 0 instead of 9.

3. How does a binary matrix become histograms?

Show answer

For each row, column j's height is the number of consecutive 1s ending at that row (reset to 0 at a 0). Every all-1s rectangle has its bottom edge on some row, where it's a rectangle under that row's histogram.

Key takeaways

  • For each bar, the best rectangle spans from the nearest shorter bar on the left to the nearest shorter on the right.
  • Pop when the current bar is shorter; width = i - newTop - 1 (or i if the stack is empty).
  • Append a height-0 bar to flush the stack.
  • Binary matrix: per-row heights of consecutive 1s, then the histogram answer per row.

Quick revise

The whole skill on one page, for the night before an interview.

This page puts the lesson and the deep dive together. Skim it before practice or an interview, and go back to the full lesson for anything you don't recognize.

Pick the tool

You needUse
Largest histogram rectangleincreasing stack
Largest rectangle of 1srow heights + histogram
Largest square of 1smin-of-three DP
Count all-1 rectanglesrow heights + stack counts
Trapped waterstack layers or two pointers

Snippets worth knowing by heart

Java

for (int i = 0; i <= n; i++) {
    int cur = i == n ? 0 : h[i];                                   // flush with a 0
    while (!st.isEmpty() && h[st.peek()] >= cur) {
        int height = h[st.pop()];
        int width = st.isEmpty() ? i : i - st.peek() - 1;
        best = Math.max(best, (long) height * width);              // long: no overflow
    }
    st.push(i);
}

Python

d[r + 1][c + 1] = min(d[r][c + 1], d[r + 1][c], d[r][c]) + 1   # largest square ending at (r, c)

The traps

  • No final flush: [1, 2, 3, 4, 5] returns 0. Push a height-0 bar at index n.
  • The width formula: measuring from the popped index makes rectangles too narrow. Use i - newTop - 1, or i when empty.
  • int areas: height x width overflows. Multiply in long.
  • No reset at a 0 in the matrix: towers span gaps and overstate the area. Set the height to 0 at a 0 cell.

Staff-level points, one line each

  • Expanding from every bar: 180,588 steps for 10,000 random bars, 49,995,000 for sorted ones.
  • Trapping rain water: stack layers and two pointers both matched brute force.
  • All-1 rectangles: count[p] + h[j] x (j - p); it matched brute force on 300 grids.
  • Squares use min-of-three; a 1 x 5 row has square 1 and rectangle 5.
  • 100,000 bars of 10^9: an int gave 2147447808 instead of 10^14.

Say it in an interview

  • "Each bar's best rectangle spans from its nearest shorter bar on the left to the one on the right."
  • "A final zero-height bar flushes the stack."
  • "A matrix of 1s is a histogram per row."
  • "For squares there's a simpler DP, but rectangles need the stack."

Practice

This skill comes with 8 multiple-choice questions that tell you which misconception a wrong answer reveals and 2 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Monotonic Stack Area Computation free

Largest Rectangle in Histogram

HardProCoding problemJava · Python

Bars of width 1 stand side by side, with heights heights. Find the largest rectangle that fits under them, lined up with the bars, and return its area.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Maximal Rectangle

HardProCoding problemJava · Python

In a grid of 0s and 1s, find the biggest rectangle made only of 1s and return its area.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Monotonic Stack Area Computation free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime