Maximal Rectangle looks intimidating — a 2-D grid, find the biggest block of 1s — but it secretly reduces to a problem you may already know: largest rectangle in a histogram. The trick is to turn each row of the grid into a histogram and reuse the monotonic-stack solution.
Problem. Given a binary matrix filled with 0s and 1s, find the largest rectangle containing
only 1s and return its area.
Example: for the matrix below, the answer is 6 — the 2×3 block of 1s spanning rows 1–2 and columns 1–3.
1 0 1 0
1 1 1 1
0 1 1 1The slow way first
The brute force is brutal: pick every pair of corners for a candidate rectangle and check that every cell inside is a 1. There are O((rows·cols)²) corner pairs and each check scans the rectangle, landing somewhere around O(rows² · cols²) or worse. For anything but a tiny grid that is hopeless.
The question to ask: what sub-problem do I already know how to solve fast? If I look at just one row and ask "how tall is the column of 1s ending at this row," I get a histogram — and largest-rectangle-in-a-histogram is a clean O(n) monotonic-stack problem.
The idea: turn each row into a histogram
Sweep the grid top to bottom while keeping a heights array, one entry per column:
- If
matrix[row][c] == 1, the column of 1s got one taller:heights[c] += 1. - If it is
0, the column is broken, so the height resets to0.
After updating heights for a row, that array is a histogram of consecutive 1s ending on this row. Run largest rectangle in histogram on it and keep the global maximum. Any all-1s rectangle in the grid has some bottom row, and on that row it shows up as a rectangle in the histogram — so we are guaranteed to see it.
The histogram solver itself uses a stack of column indices whose heights are strictly increasing; when a shorter bar arrives we pop and measure each rectangle. Here we treat it as a reusable building block.
Walk through it
Step through the animation. The grid sweeps row by row. The heights row underneath grows by 1 where a cell is a 1 and snaps to 0 where it is a 0. After each row we read off the best rectangle in that histogram. Row 0 gives 1, row 1 gives 4 (a width-4 bar of height 1), and row 2 gives 6 (height 2 across columns 1–3) — the final answer.
Pseudocode
cols = number of columns
heights = array of cols zeros
best = 0
for each row in matrix:
for each column c:
if matrix[row][c] == 1: heights[c] += 1 # column got taller
else: heights[c] = 0 # column broken, reset
area = largest_rectangle(heights) # monotonic-stack solver
best = max(best, area)
return bestThe Python solution
def maximal_rectangle(matrix):
cols = len(matrix[0])
heights = [0] * cols
best = 0
for row in matrix:
for c in range(cols):
# extend the column or reset it to 0
heights[c] = heights[c] + 1 if row[c] == 1 else 0
area = largest_rectangle(heights) # monotonic stack
best = max(best, area)
return bestheights[c]is how many consecutive 1s sit in columncending at the current row.- The inner loop is the histogram update:
+1when the cell is a 1, hard reset to0when it is a 0. largest_rectangle(heights)is the standard monotonic-stack histogram solver (see that lesson) — it returns the biggest rectangle area for the current row in O(cols).- We take
maxover every row, because each candidate rectangle is measured on its bottom row.
Complexity
| Case | Time | Notes |
|---|---|---|
| Brute force (all corner pairs) | O(rows² · cols²) (moderate) | check every candidate rectangle |
| Histogram per row (this solution) | O(rows · cols) (moderate) | O(cols) stack pass per row |
O(cols) (moderate)Each row costs one linear histogram pass, and there are rows of them, so the whole thing is O(rows · cols) — we touch each cell a constant number of times. The only extra memory is the single heights row, O(cols).
When this pattern shows up
When a 2-D grid problem asks for the biggest rectangle or area of some shape, ask whether you can reduce it to a 1-D problem per row by accumulating a running quantity down each column. Maximal Rectangle and "maximal square" both collapse to a per-row scan over running heights.
Do not forget the reset: when a cell is 0, that column height must drop to 0, not just stop
growing. Forgetting it lets a rectangle pass through a hole of 0s, which silently overcounts the area.
Practice
After processing row 1 = [1, 1, 1, 1], heights = [2, 1, 2, 1]. What is the largest rectangle in that histogram, and why is it not 2?
1. What does heights[c] represent after processing a row?
2. Why does Maximal Rectangle reduce to Largest Rectangle in a Histogram?
3. What must happen to heights[c] when the cell is 0?
4. What is the overall time complexity?