Given an m x n binary matrix mat, return the number of submatrices that have all ones.
Example 1:
Input: mat = [[1,0,1],[1,1,0],[1,1,0]]
Output: 13
Explanation:
There are 6 rectangles of side 1x1.
There are 2 rectangles of side 1x2.
There are 3 rectangles of side 2x1.
There is 1 rectangle of side 2x2.
There is 1 rectangle of side 3x1.
Total number of rectangles = 6 + 2 + 3 + 1 + 1 = 13.
Example 2:
Input: mat = [[0,1,1,0],[0,1,1,1],[1,1,1,0]]
Output: 24
Explanation:
There are 8 rectangles of side 1x1.
There are 5 rectangles of side 1x2.
There are 2 rectangles of side 1x3.
There are 4 rectangles of side 2x1.
There are 2 rectangles of side 2x2.
There are 2 rectangles of side 3x1.
There is 1 rectangle of side 3x2.
Total number of rectangles = 8 + 5 + 2 + 4 + 2 + 2 + 1 = 24.
Constraints:
1 <= m, n <= 150
mat[i][j] is either 0 or 1.
Solutions
Solution 1: Enumeration + Prefix Sum
Thinking
Counting all-\(1\) submatrices by enumerating four borders and scanning the interior is far too slow. Even a 2D prefix-sum check over every pair of corners is \(O(m^2 n^2)\). With side length up to \(150\), we need to drop one nested loop.
After fixing the bottom-right cell \((i,j)\), a submatrix is determined by how far we extend upward. Precompute \(g[i][j]\) as the run of ones ending at that cell in its row. Walking \(k\) upward from \(i\) and taking the running minimum of \(g[k][j]\) gives the legal width for each height; add that width at every step. Each corner is then processed in \(O(m)\), for \(O(m^2 n)\) overall.
We can enumerate the bottom-right corner \((i, j)\) of the matrix, and then enumerate the first row \(k\) upwards. The width of the matrix with \((i, j)\) as the bottom-right corner in each row is \(\min_{k \leq i} \textit{g}[k][j]\), where \(\textit{g}[k][j]\) represents the width of the matrix with \((k, j)\) as the bottom-right corner in the \(k\)-th row.
Therefore, we can preprocess a 2D array \(g[i][j]\), where \(g[i][j]\) represents the number of consecutive \(1\)s from the \(j\)-th column to the left in the \(i\)-th row.
The time complexity is \(O(m^2 \times n)\), and the space complexity is \(O(m \times n)\). Here, \(m\) and \(n\) are the number of rows and columns of the matrix, respectively.
/** * @param {number[][]} mat * @return {number} */varnumSubmat=function(mat){constm=mat.length;constn=mat[0].length;constg=Array.from({length:m},()=>Array(n).fill(0));for(leti=0;i<m;i++){for(letj=0;j<n;j++){if(mat[i][j]){g[i][j]=j===0?1:1+g[i][j-1];}}}letans=0;for(leti=0;i<m;i++){for(letj=0;j<n;j++){letcol=Infinity;for(letk=i;k>=0;k--){col=Math.min(col,g[k][j]);ans+=col;}}}returnans;};
Solution 2: Monotonic Stack
Thinking
Solution 1 still walks \(O(m)\) rows upward at every bottom-right cell and adds the running minimum width, so the total stays \(O(m^2 \times n)\). With side length \(150\), that inner scan is the remaining cost.
A narrower width on the same column caps every row above it, so those rows do not need another pass. One strictly increasing stack of widths per column makes the stack top the nearest smaller width above the current cell. Between that top and the current row the minimum width is \(g[i][j]\), and the answer at the top and above is already stored. Each cell is pushed and popped at most once, which turns the upward scan into amortized \(O(1)\).
We still preprocess a 2D array \(g\), where \(g[i][j]\) is the number of consecutive \(1\)s from column \(j\) to the left in row \(i\).
The count is then taken column by column. For column \(j\), scan row \(i\) from top to bottom and keep a monotonic stack of triples \((w, r, c)\): the width \(w\), the row \(r\), and the number \(c\) of all-\(1\) submatrices whose bottom-right corner is \((r, j)\). Widths on the stack stay strictly increasing.
When handling \(g[i][j]\), pop every stack top whose width is at least the current value. If the stack is empty, every row from \(0\) through \(i\) has minimum width \(g[i][j]\), so there are \(g[i][j] \times (i + 1)\) submatrices with bottom-right corner \((i, j)\). Otherwise let the top be \((w, r, c)\). The contribution of row \(r\) and above is already stored in \(c\), and every row from \(r + 1\) through \(i\) has minimum width \(g[i][j]\), so the count is \(c + g[i][j] \times (i - r)\). Add this value to the answer, then push the current width, the row index, and the count onto the stack.
The time complexity is \(O(m \times n)\), and the space complexity is \(O(m \times n)\). Here, \(m\) and \(n\) are the number of rows and columns of the matrix, respectively.