Count Submatrices With All Ones
MediumUpdated: Aug 21, 2025
Practice on:
Problem
Given an m x n binary matrix mat, return the number ofsubmatrices that have all ones.
Examples
Example 1
\Huge
\begin{array}{|c|c|c|}
\hline
1 & 0 & 1 \\\
\hline
1 & 1 & 0 \\\
\hline
1 & 1 & 0 \\\
\hline
\end{array}
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
\Huge
\begin{array}{|c|c|c|c|}
\hline
0 & 1 & 1 & 0\\\
\hline
0 & 1 & 1 & 1 \\\
\hline
1 & 1 & 1 & 0 \\\
\hline
\end{array}
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 <= 150mat[i][j]is either0or1.
Solution
Method 1 – Histogram + Monotonic Stack
Intuition
We can treat each row as the base of a histogram, where the height at each column is the number of consecutive ones above (including the current row). For each row, we use a monotonic stack to efficiently count the number of submatrices ending at that row.
Approach
- For each row, update the histogram heights for each column.
- For each row, use a monotonic stack to count the number of rectangles ending at each column:
- For each column, pop from the stack until the top is less than the current height.
- The width is the distance to the previous smaller height.
- The number of submatrices ending at (i, j) is the height times the width, plus the count from the previous smaller height.
- Sum the counts for all positions.
- Return the total count.
Code
C++
class Solution {
public:
int numSubmat(vector<vector<int>>& mat) {
int m = mat.size(), n = mat[0].size(), ans = 0;
vector<int> h(n);
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j)
h[j] = mat[i][j] ? h[j] + 1 : 0;
vector<int> stack, sum(n);
for (int j = 0; j < n; ++j) {
while (!stack.empty() && h[stack.back()] >= h[j]) stack.pop_back();
if (!stack.empty()) {
int prev = stack.back();
sum[j] = sum[prev] + h[j] * (j - prev);
} else {
sum[j] = h[j] * (j + 1);
}
ans += sum[j];
stack.push_back(j);
}
}
return ans;
}
};
Go
func numSubmat(mat [][]int) int {
m, n := len(mat), len(mat[0])
h := make([]int, n)
ans := 0
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if mat[i][j] == 1 {
h[j]++
} else {
h[j] = 0
}
}
stack, sum := []int{}, make([]int, n)
for j := 0; j < n; j++ {
for len(stack) > 0 && h[stack[len(stack)-1]] >= h[j] {
stack = stack[:len(stack)-1]
}
if len(stack) > 0 {
prev := stack[len(stack)-1]
sum[j] = sum[prev] + h[j]*(j-prev)
} else {
sum[j] = h[j]*(j+1)
}
ans += sum[j]
stack = append(stack, j)
}
}
return ans
}
Java
class Solution {
public int numSubmat(int[][] mat) {
int m = mat.length, n = mat[0].length, ans = 0;
int[] h = new int[n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
h[j] = mat[i][j] == 1 ? h[j] + 1 : 0;
int[] stack = new int[n], sum = new int[n];
int top = -1;
for (int j = 0; j < n; j++) {
while (top >= 0 && h[stack[top]] >= h[j]) top--;
if (top >= 0) {
int prev = stack[top];
sum[j] = sum[prev] + h[j] * (j - prev);
} else {
sum[j] = h[j] * (j + 1);
}
ans += sum[j];
stack[++top] = j;
}
}
return ans;
}
}
Kotlin
class Solution {
fun numSubmat(mat: Array<IntArray>): Int {
val m = mat.size; val n = mat[0].size
val h = IntArray(n)
var ans = 0
for (i in 0 until m) {
for (j in 0 until n) h[j] = if (mat[i][j] == 1) h[j] + 1 else 0
val stack = mutableListOf<Int>()
val sum = IntArray(n)
for (j in 0 until n) {
while (stack.isNotEmpty() && h[stack.last()] >= h[j]) stack.removeAt(stack.size-1)
if (stack.isNotEmpty()) {
val prev = stack.last()
sum[j] = sum[prev] + h[j] * (j - prev)
} else {
sum[j] = h[j] * (j + 1)
}
ans += sum[j]
stack.add(j)
}
}
return ans
}
}
Python
class Solution:
def numSubmat(self, mat: list[list[int]]) -> int:
m, n = len(mat), len(mat[0])
h = [0] * n
ans = 0
for i in range(m):
for j in range(n):
h[j] = h[j] + 1 if mat[i][j] else 0
stack, sum_ = [], [0] * n
for j in range(n):
while stack and h[stack[-1]] >= h[j]:
stack.pop()
if stack:
prev = stack[-1]
sum_[j] = sum_[prev] + h[j] * (j - prev)
else:
sum_[j] = h[j] * (j + 1)
ans += sum_[j]
stack.append(j)
return ans
Rust
impl Solution {
pub fn num_submat(mat: Vec<Vec<i32>>) -> i32 {
let m = mat.len();
let n = mat[0].len();
let mut h = vec![0; n];
let mut ans = 0;
for i in 0..m {
for j in 0..n {
h[j] = if mat[i][j] == 1 { h[j] + 1 } else { 0 };
}
let mut stack = vec![];
let mut sum = vec![0; n];
for j in 0..n {
while let Some(&last) = stack.last() {
if h[last] >= h[j] { stack.pop(); } else { break; }
}
if let Some(&prev) = stack.last() {
sum[j] = sum[prev] + h[j] * (j - prev) as i32;
} else {
sum[j] = h[j] * (j + 1) as i32;
}
ans += sum[j];
stack.push(j);
}
}
ans
}
}
TypeScript
class Solution {
numSubmat(mat: number[][]): number {
const m = mat.length, n = mat[0].length;
const h = Array(n).fill(0);
let ans = 0;
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++)
h[j] = mat[i][j] ? h[j] + 1 : 0;
const stack: number[] = [], sum: number[] = Array(n).fill(0);
for (let j = 0; j < n; j++) {
while (stack.length && h[stack[stack.length-1]] >= h[j]) stack.pop();
if (stack.length) {
const prev = stack[stack.length-1];
sum[j] = sum[prev] + h[j] * (j - prev);
} else {
sum[j] = h[j] * (j + 1);
}
ans += sum[j];
stack.push(j);
}
}
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(m * n), since we process each cell once per row. - 🧺 Space complexity:
O(n), for the histogram and stack per row.