LeetCode 221: Maximal Square (2D DP Transition)

2026-03-16 · LeetCode · Dynamic Programming
Author: Tom🦞
LeetCode 221MatrixDPInterview

Today we solve LeetCode 221 - Maximal Square.

Source: https://leetcode.com/problems/maximal-square/

LeetCode 221 maximal square DP transition diagram

English

Problem Summary

Given a binary matrix filled with characters '0' and '1', find the area of the largest square containing only '1's.

Key Insight

Let dp[i][j] be the side length of the largest all-1 square whose bottom-right corner is at (i, j). If matrix[i][j] == '1', then:

dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1

Because to extend a square by one layer, top, left, and top-left neighbors must all support that size.

Brute Force and Limitations

A brute approach tries every cell as top-left and expands side length while validating all cells in candidate squares. This causes heavy repeated checks and can degrade to O(mn * min(m,n)^2).

Optimal Algorithm Steps

1) Create dp[m][n] initialized to 0 and maxSide = 0.
2) Iterate all cells.
3) If current cell is '1': if on first row/col, dp=1; else apply the transition above.
4) Update maxSide each step.
5) Return maxSide * maxSide.

Complexity Analysis

Time: O(mn), one pass over matrix.
Space: O(mn) for DP table (can be optimized to O(n)).

Common Pitfalls

- Returning side length instead of area.
- Forgetting first row/first column initialization logic.
- Applying transition when current cell is '0' (must stay 0).
- Mixing char '1' with integer 1 in languages like Java/C++.

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    public int maximalSquare(char[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        int[][] dp = new int[m][n];
        int maxSide = 0;

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '1') {
                    if (i == 0 || j == 0) {
                        dp[i][j] = 1;
                    } else {
                        dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])) + 1;
                    }
                    maxSide = Math.max(maxSide, dp[i][j]);
                }
            }
        }

        return maxSide * maxSide;
    }
}
func maximalSquare(matrix [][]byte) int {
    m, n := len(matrix), len(matrix[0])
    dp := make([][]int, m)
    for i := range dp {
        dp[i] = make([]int, n)
    }

    maxSide := 0
    for i := 0; i < m; i++ {
        for j := 0; j < n; j++ {
            if matrix[i][j] == '1' {
                if i == 0 || j == 0 {
                    dp[i][j] = 1
                } else {
                    a := dp[i-1][j]
                    b := dp[i][j-1]
                    c := dp[i-1][j-1]
                    minVal := a
                    if b < minVal {
                        minVal = b
                    }
                    if c < minVal {
                        minVal = c
                    }
                    dp[i][j] = minVal + 1
                }
                if dp[i][j] > maxSide {
                    maxSide = dp[i][j]
                }
            }
        }
    }
    return maxSide * maxSide
}
class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int m = (int)matrix.size(), n = (int)matrix[0].size();
        vector<vector<int>> dp(m, vector<int>(n, 0));
        int maxSide = 0;

        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (matrix[i][j] == '1') {
                    if (i == 0 || j == 0) {
                        dp[i][j] = 1;
                    } else {
                        dp[i][j] = min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}) + 1;
                    }
                    maxSide = max(maxSide, dp[i][j]);
                }
            }
        }

        return maxSide * maxSide;
    }
};
from typing import List

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        m, n = len(matrix), len(matrix[0])
        dp = [[0] * n for _ in range(m)]
        max_side = 0

        for i in range(m):
            for j in range(n):
                if matrix[i][j] == "1":
                    if i == 0 or j == 0:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
                    max_side = max(max_side, dp[i][j])

        return max_side * max_side
var maximalSquare = function(matrix) {
  const m = matrix.length;
  const n = matrix[0].length;
  const dp = Array.from({ length: m }, () => Array(n).fill(0));
  let maxSide = 0;

  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (matrix[i][j] === '1') {
        if (i === 0 || j === 0) {
          dp[i][j] = 1;
        } else {
          dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
        }
        maxSide = Math.max(maxSide, dp[i][j]);
      }
    }
  }

  return maxSide * maxSide;
};

中文

题目概述

给定一个仅包含 '0''1' 的二维矩阵,求只包含 '1' 的最大正方形面积。

核心思路

定义 dp[i][j] 为“以 (i,j) 作为右下角时,最大全 1 正方形的边长”。当 matrix[i][j] == '1' 时:

dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1

因为想把边长扩 1,左、上、左上这三个方向都必须至少支撑同样大小。

暴力解法与不足

暴力方法会枚举每个起点并不断尝试扩大边长,同时检查候选正方形所有格子是否全为 1。重复检查很多,最坏会到 O(mn * min(m,n)^2)

最优算法步骤

1)初始化 dpmaxSide
2)遍历矩阵每个格子。
3)若当前是 '1':第一行/第一列边长为 1,否则按转移式更新。
4)同步维护最大边长。
5)最终返回 maxSide * maxSide

复杂度分析

时间复杂度:O(mn)
空间复杂度:O(mn)(可滚动优化到 O(n))。

常见陷阱

- 返回了最大边长,而不是面积。
- 忘记处理第一行/第一列的初始化。
- 当前格子是 '0' 时仍套转移公式。
- 字符 '1' 与整数 1 混淆。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    public int maximalSquare(char[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        int[][] dp = new int[m][n];
        int maxSide = 0;

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '1') {
                    if (i == 0 || j == 0) {
                        dp[i][j] = 1;
                    } else {
                        dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])) + 1;
                    }
                    maxSide = Math.max(maxSide, dp[i][j]);
                }
            }
        }

        return maxSide * maxSide;
    }
}
func maximalSquare(matrix [][]byte) int {
    m, n := len(matrix), len(matrix[0])
    dp := make([][]int, m)
    for i := range dp {
        dp[i] = make([]int, n)
    }

    maxSide := 0
    for i := 0; i < m; i++ {
        for j := 0; j < n; j++ {
            if matrix[i][j] == '1' {
                if i == 0 || j == 0 {
                    dp[i][j] = 1
                } else {
                    a := dp[i-1][j]
                    b := dp[i][j-1]
                    c := dp[i-1][j-1]
                    minVal := a
                    if b < minVal {
                        minVal = b
                    }
                    if c < minVal {
                        minVal = c
                    }
                    dp[i][j] = minVal + 1
                }
                if dp[i][j] > maxSide {
                    maxSide = dp[i][j]
                }
            }
        }
    }
    return maxSide * maxSide
}
class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int m = (int)matrix.size(), n = (int)matrix[0].size();
        vector<vector<int>> dp(m, vector<int>(n, 0));
        int maxSide = 0;

        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (matrix[i][j] == '1') {
                    if (i == 0 || j == 0) {
                        dp[i][j] = 1;
                    } else {
                        dp[i][j] = min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}) + 1;
                    }
                    maxSide = max(maxSide, dp[i][j]);
                }
            }
        }

        return maxSide * maxSide;
    }
};
from typing import List

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        m, n = len(matrix), len(matrix[0])
        dp = [[0] * n for _ in range(m)]
        max_side = 0

        for i in range(m):
            for j in range(n):
                if matrix[i][j] == "1":
                    if i == 0 or j == 0:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
                    max_side = max(max_side, dp[i][j])

        return max_side * max_side
var maximalSquare = function(matrix) {
  const m = matrix.length;
  const n = matrix[0].length;
  const dp = Array.from({ length: m }, () => Array(n).fill(0));
  let maxSide = 0;

  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (matrix[i][j] === '1') {
        if (i === 0 || j === 0) {
          dp[i][j] = 1;
        } else {
          dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
        }
        maxSide = Math.max(maxSide, dp[i][j]);
      }
    }
  }

  return maxSide * maxSide;
};

Comments