Maximal Rectangle
Given a rows x cols binary matrix filled with '0's and '1's, find the largest rectangle containing only '1's and return its area.
- rows == matrix.length
- cols == matrix[i].length
- 1 <= rows, cols <= 200
- matrix[i][j] is '0' or '1'
matrix = [['1','0','1','0','0'],['1','0','1','1','1'],['1','1','1','1','1'],['1','0','0','1','0']]6A rectangle of all 1s in a 2D grid sounds much harder than any 1D problem, until you slice it by rows. Treat each row as the ground and look at the columns standing on it: a column's "bar height" is how many consecutive 1s stack up directly above that cell, ending on this row. A 0 snaps that column's height back to 0, because no all-1s rectangle can pass through a 0. Now the biggest all-1s rectangle whose bottom edge rests on this row is exactly the largest rectangle in this row's bar chart. Sweep the rows top to bottom, updating the heights as you go, and the answer is the best row-histogram you ever see.
So the whole problem reduces to solving "largest rectangle in a histogram" once per row. Here's how that 1D solve works, since it carries all the weight. Any rectangle in a histogram is limited by its shortest bar, so for each bar we want the widest span where it is the shortest — bounded on each side by the nearest strictly shorter bar. Finding those nearest-shorter neighbors in one pass is the job of a monotonic stack: a normal push/pop stack whose bar heights we keep increasing from bottom to top. Scanning left to right, when the current bar is shorter than the one on top, the current column is that top bar's right wall — pop it, its left wall is the new top (nearest shorter bar to its left, because the stack rises), and its area is height × (right − left − 1). Keep popping while the current bar stays shorter, then push. A height-0 sentinel at the end flushes whatever's left.
def maximal_rectangle(matrix):
if not matrix:
return 0
cols = len(matrix[0])
heights = [0] * cols
best = 0
for row in matrix:
for c in range(cols):
heights[c] = heights[c] + 1 if row[c] == '1' else 0 # grow, or reset on a 0
best = max(best, largest_in_histogram(heights))
return best
def largest_in_histogram(heights):
bars = heights + [0] # sentinel forces every remaining bar to be measured
stack = [-1] # sentinel left wall
best = 0
for i in range(len(bars)):
while len(stack) > 1 and bars[i] < bars[stack[-1]]:
h = bars[stack.pop()]
w = i - stack[-1] - 1
best = max(best, h * w)
stack.append(i)
return bestEach row costs one linear histogram pass (every column pushed and popped once), so the total work is proportional to the number of cells in the grid.
['1','0'] → heights [1, 0]; largest histogram rectangle is 1.['1','1'] → heights [2, 1]; the height-1 bar spans both columns for area 2, beating the lone height-2 bar.2D Matrix to Histogram Strategy
Key Strategy
Histogram Evolution: At each row, update heights based on consecutive 1s.
Monotonic Stack: Solve the Largest Rectangle in Histogram for each row.
Dynamic Reduction
The core insight is to transform the 2D grid problem into multiple 1D histogram problems. For each row, calculate how many consecutive '1's exist ending at that cell.