class Solution:
def maximalSquare(self, matrix):
if not matrix or not matrix[0]:
return 0
rows, cols = len(matrix), len(matrix[0])
dp = [[0] * (cols + 1) for _ in range(rows + 1)]
max_side = 0
for i in range(1, rows + 1):
for j in range(1, cols + 1):
if matrix[i - 1][j - 1] == '1':
dp[i][j] = min(
dp[i][j - 1],
dp[i - 1][j],
dp[i - 1][j - 1]
) + 1
max_side = max(max_side, dp[i][j])
return max_side * max_side
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
if (matrix.empty() || matrix[0].empty()) return 0;
int rows = matrix.size(), cols = matrix[0].size();
vector<vector<int>> dp(rows + 1, vector<int>(cols + 1, 0));
int maxSide = 0;
for (int i = 1; i <= rows; ++i) {
for (int j = 1; j <= cols; ++j) {
if (matrix[i-1][j-1] == '1') {
dp[i][j] = min({dp[i][j-1], dp[i-1][j], dp[i-1][j-1]}) + 1;
maxSide = max(maxSide, dp[i][j]);
}
}
}
return maxSide * maxSide;
}
};
class Solution {
public int maximalSquare(char[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return 0;
int rows = matrix.length, cols = matrix[0].length;
int[][] dp = new int[rows + 1][cols + 1];
int maxSide = 0;
for (int i = 1; i <= rows; i++) {
for (int j = 1; j <= cols; j++) {
if (matrix[i - 1][j - 1] == '1') {
dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
maxSide = Math.max(maxSide, dp[i][j]);
}
}
}
return maxSide * maxSide;
}
}
var maximalSquare = function(matrix) {
if (!matrix || matrix.length === 0 || matrix[0].length === 0) return 0;
const rows = matrix.length, cols = matrix[0].length;
const dp = Array.from({length: rows + 1}, () => Array(cols + 1).fill(0));
let maxSide = 0;
for (let i = 1; i <= rows; i++) {
for (let j = 1; j <= cols; j++) {
if (matrix[i - 1][j - 1] === '1') {
dp[i][j] = Math.min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1;
maxSide = Math.max(maxSide, dp[i][j]);
}
}
}
return maxSide * maxSide;
};
matrix
filled with '0'
s and '1'
s, find the largest square containing only '1'
s and return its area.
m x n
where each element is either '0'
or '1'
.'1'
s.'1'
. This is simple but very inefficient, especially for large matrices.
Upon inspection, we notice that for any cell (i, j)
to be the bottom-right corner of a square of size k
, the cells to the left, above, and diagonally up-left must also be able to form squares of size at least k-1
. This observation leads us to dynamic programming, where we can build solutions for larger squares based on solutions for smaller ones.
The key shift is from checking every possible square (brute-force) to efficiently building up the answer using previously computed information (dynamic programming).
dp
) with dimensions (rows+1) x (cols+1)
, initialized to 0. This extra row and column simplify boundary checks.(i, j)
in the matrix:
matrix[i-1][j-1]
is '1'
, set dp[i][j]
to 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
.(i, j)
is limited by the smallest square among its top, left, and top-left neighbors.Consider the following input matrix:
[ ['1', '0', '1', '0', '0'], ['1', '0', '1', '1', '1'], ['1', '1', '1', '1', '1'], ['1', '0', '0', '1', '0'] ]
dp[3][3] = min(2,2,1) + 1 = 2
.dp[3][4] = min(2,1,2) + 1 = 2
.dp[3][5] = min(2,2,2) + 1 = 3
.O((mn)^2)
— For each cell, we may check all possible square sizes.O(1)
— Only constant extra space is needed.O(mn)
— Each cell is visited once and updated in constant time.O(mn)
— For the DP table. This can be reduced to O(n)
if only the previous row is kept.O(mn)
solution. The approach is both intuitive and efficient, making it a classic example of dynamic programming in 2D grids.