Lesson 154 of 164
Maximal Square
Given a matrix of 0s and 1s, find the largest square that contains only 1s and return its area.
LeetCode: 221. Maximal Square
Example
1 1 1 1 0
1 1 1 1 1 Output: 9 (a 3 × 3 square, for example the top-left one)
1 1 1 1 1
0 1 0 0 0Brute force: grow a square from every cell
Use every 1 as the top-left corner of a square, and grow the square one row and column at a time while the new row and column are all 1s.
public class Main {
// true if the new bottom row and right column for a square of side size + 1 are all 1s
static boolean canGrow(int[][] m, int r, int c, int size) {
for (int k = 0; k <= size; k++) {
if (m[r + size][c + k] != 1 || m[r + k][c + size] != 1) return false;
}
return true;
}
static int maximalSquare(int[][] m) {
int rows = m.length, cols = m[0].length;
int best = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
int size = 0;
while (r + size < rows && c + size < cols && canGrow(m, r, c, size)) {
size++;
}
best = Math.max(best, size);
}
}
return best * best;
}
public static void main(String[] args) {
int[][] m = {{1, 1, 1, 1, 0}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {0, 1, 0, 0, 0}};
System.out.println(maximalSquare(m));
}
}9Time: O(r · c · s²) for a largest square of side s. Space: O(1).
Optimal: grow squares from their neighbours
Let side[i][j] be the side of the largest all-1 square whose bottom-right corner is (i, j). If the cell is 1, that square is limited by the squares ending at its top, left, and top-left neighbours:
side[i][j] = 1 + min(side[i-1][j], side[i][j-1], side[i-1][j-1]) if m[i][j] == 1
side[i][j] = 0 otherwiseIf all three neighbours end squares of side at least k, together they cover a (k + 1) × (k + 1) square ending at (i, j). If any of them is smaller, it has a 0 that also blocks the larger square.
public class Main {
static int maximalSquare(int[][] m) {
int cols = m[0].length;
int[] prev = new int[cols + 1]; // side[i - 1][..], shifted by one column
int best = 0;
for (int[] row : m) {
int[] cur = new int[cols + 1];
for (int j = 1; j <= cols; j++) {
if (row[j - 1] == 1) {
cur[j] = 1 + Math.min(prev[j], Math.min(cur[j - 1], prev[j - 1]));
best = Math.max(best, cur[j]);
}
}
prev = cur;
}
return best * best;
}
public static void main(String[] args) {
int[][] m = {{1, 1, 1, 1, 0}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {0, 1, 0, 0, 0}};
System.out.println(maximalSquare(m));
int[][] m2 = {
{0, 0, 0, 0, 1, 1},
{0, 1, 1, 1, 1, 0},
{0, 1, 1, 1, 1, 0},
{0, 1, 1, 1, 1, 0},
{1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0},
};
System.out.println(maximalSquare(m2) + " " + maximalSquare(new int[][]{{0}}));
}
}9
16 0Time: O(r · c). Space: O(c): only the previous row is kept. An extra column of zeros on the left removes the special case for j = 0.
Edge cases
- No
1s: area0. - Largest rectangle instead of square: see Largest Rectangle in a Histogram, applied row by row.
