Count Square Submatrices with All Ones

Solve this Problem
Medium20–25 min
Topics
Companies
Practice:LeetCode ↗
Given a binary matrix, count how many square submatrices — of any size, 1×1 and up — are made entirely of 1s. Trying every square directly, with a prefix-sum table to check each one in O(1), already works. The faster way notices something sharper: define dp[r][c] as the side length of the biggest all-1s square that has its bottom-right corner exactly at (r, c). That value can only grow past 1 if a square one size smaller already ends at the cell above, the cell to the left, *and* the cell diagonally above-left — so dp[r][c] is the smallest of those three neighbors, plus one. The neat payoff: dp[r][c] doesn't just say how big the largest square there is, it also equals how many squares of every size up to that end there — a size-3 square ending somewhere means a size-2 and a size-1 do too, at the very same corner. Summing dp[r][c] across the whole grid is the answer.

Test Case 1:

Input:matrix = [[1,0,1],[1,1,0],[1,1,1]]
Output:8
Explanation:6 squares of size 1×1, plus a 2×2 square with its bottom-right corner at row 2, column 1 — that one 2×2 accounts for 2 more toward the total (1×1 squares are already counted, so it adds just the size-2 count).

Test Case 2:

Input:matrix = [[0,1,1],[1,1,1],[0,1,1]]
Output:9
Explanation:7 size-1×1 squares and 2 size-2×2 squares (one in the top-right area, one in the bottom-right).

Test Case 3:

Input:matrix = [[0,0],[0,0]]
Output:0
Explanation:No 1s at all, so no square — not even a 1×1 one.

Constraints

  • 1 ≤ rows, cols ≤ 200
  • every entry of matrix is either 0 or 1
🚀

Try the Dry Run

Don't just read the solution — watch it execute, one step at a time.

Approach & Solutions

Brute Force — Prefix Sums Over Every Candidate Square

Brute

For every possible top-left corner, try every possible square size that still fits within the grid from there, and use a 2D prefix-sum table to check in O(1) whether that size×size region is entirely 1s. There are O(R·C) starting corners and up to O(min(R,C)) sizes to try from each one.

TimeO(R · C · min(R, C))
SpaceO(R · C)
1class Solution { 2 public int countSquares(int[][] matrix) { 3 int rows = matrix.length; 4 if (rows == 0) return 0; 5 int cols = matrix[0].length; 6 int[][] prefix = new int[rows + 1][cols + 1]; 7 for (int r = 0; r < rows; r++) { 8 for (int c = 0; c < cols; c++) { 9 prefix[r + 1][c + 1] = matrix[r][c] + prefix[r][c + 1] + prefix[r + 1][c] - prefix[r][c]; 10 } 11 } 12 int count = 0; 13 for (int top = 0; top < rows; top++) { 14 for (int left = 0; left < cols; left++) { 15 int maxSize = Math.min(rows - top, cols - left); 16 for (int size = 1; size <= maxSize; size++) { 17 int bottom = top + size - 1; 18 int right = left + size - 1; 19 int sum = prefix[bottom + 1][right + 1] - prefix[top][right + 1] - prefix[bottom + 1][left] + prefix[top][left]; 20 if (sum == size * size) { 21 count++; 22 } 23 } 24 } 25 } 26 return count; 27 } 28}

Optimal — DP: Largest Square Ending at Each Cell

Optimal

Let dp[r][c] be the side length of the largest all-1s square whose bottom-right corner is exactly cell (r, c). If matrix[r][c] is 0, no square can end there — dp[r][c] = 0. Otherwise a square of side k can only end here if squares of side k-1 already end at the cell above, the cell to the left, and the cell diagonally above-left — so dp[r][c] is one more than the smallest of those three neighbors. The key trick: dp[r][c] doesn't just tell you the biggest square ending there — it tells you exactly how many squares (of every size from 1 up to dp[r][c]) end there, since every smaller size is automatically achievable too. Summing dp[r][c] over the whole grid is the total count.

TimeO(R · C)
SpaceO(R · C)
1class Solution { 2 public int countSquares(int[][] matrix) { 3 int rows = matrix.length; 4 if (rows == 0) return 0; 5 int cols = matrix[0].length; 6 int[][] dp = new int[rows][cols]; 7 int count = 0; 8 for (int r = 0; r < rows; r++) { 9 for (int c = 0; c < cols; c++) { 10 if (matrix[r][c] == 0) { 11 dp[r][c] = 0; 12 } else if (r == 0 || c == 0) { 13 dp[r][c] = 1; 14 } else { 15 dp[r][c] = Math.min(dp[r - 1][c], Math.min(dp[r][c - 1], dp[r - 1][c - 1])) + 1; 16 } 17 count += dp[r][c]; 18 } 19 } 20 return count; 21 } 22}

Related Problems