Maximal SquareLoading saved progress…

Maximal Square

Given a matrix filled with 0s and 1s, find the largest square whose cells are all 1, and return its area. This is LeetCode 221, a classic warm-up for two-dimensional dynamic programming: the answer for each cell turns out to depend on the answers already computed for a few of its neighbours. The squares must be axis-aligned (no rotated diamonds), and if the matrix is empty the area is 0.

Signature

maximalSquare(matrix)  // 2D array of 0/1 -> area of the largest all-1 square

matrix is a rectangular 2D array of numbers 0 and 1. Return a single number: the area (side length squared), not the side length.

Examples

maximalSquare([
  [1, 0, 1, 0, 0],
  [1, 0, 1, 1, 1],
  [1, 1, 1, 1, 1],
  [1, 0, 0, 1, 0],
]); // 4  — the biggest all-1 square is 2x2, so area = 2 * 2

maximalSquare([
  [1, 1, 1],
  [1, 1, 1],
  [1, 1, 1],
]); // 9  — the whole grid is one 3x3 square

maximalSquare([
  [1, 1, 1],
  [1, 0, 1],
  [1, 1, 1],
]); // 1  — the single 0 in the middle blocks any square bigger than 1x1

Notes

  • Binary matrix — every cell is 0 or 1. Cells with a "0"/"1" string are coerced with Number(), so both forms work.
  • Return the area — the answer is the side length squared. A 2x2 square returns 4, a 3x3 returns 9.
  • Axis-aligned only — the square's sides run along the rows and columns. A diagonal run of 1s is not a square.
  • Empty input — an empty matrix ([]) or a matrix with no columns ([[]]) has area 0.
  • Do not mutate — leave the input matrix unchanged; build any bookkeeping in your own array.

FAQ

What are the time and space complexity?
The dynamic-programming solution visits every cell once and does constant work per cell, so it runs in O(m*n) time for an m-by-n matrix. It uses an O(m*n) table of side lengths, which can be reduced to O(n) by keeping only the previous row.
Why does the answer multiply the side by itself?
The table tracks the side length of the largest square ending at each cell, but the problem asks for area. A square of side s has area s squared, so the final step returns maxSide * maxSide — returning maxSide alone is the single most common mistake on this problem.
Why take the minimum of three neighbours instead of two?
A square of side k+1 ending at a cell requires three smaller squares of side k to already exist: one directly above, one directly to the left, and one at the diagonal corner. The new square is limited by the smallest of the three, so you take 1 + min(top, left, top-left). Dropping the diagonal term would let an L-shaped run of ones falsely report a full square.
Loading editor…