一、Problem
Given a rows * columns matrix mat of ones and zeros, return how many submatrices have all ones.
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.
Constraints:
1 <= rows <= 150
1 <= columns <= 150
0 <= mat[i][j] <= 1
二、Solution
方法一:暴力
思路
固定一个左上角 (a, b),然后枚举右下角 (c, d),检查该两点合成的矩阵是否全 1
剪枝:如果在某一列 y 遇到了一个 0,那么以 (a, b) 为左上角时枚举右下角最多也只能枚举到 (c, y),y 后面那些列都不行了
class Solution {
public:
int numSubmat(vector<vector<int>>& g) {
int n = g.size(), m = g[0].size(), cnt = 0;
for (int a = 0; a < n; a++)
for (int b = 0; b < m; b++) {
if (g[a][b]) {
int mi = m+5;
for (int c = a; c < n; c++)
for (int d = b; d < m && d < mi; d++) {
if (g[c][d] == 1) cnt++;
else { mi = d; break; }
}
}
}
return cnt;
}
};
复杂度分析
- 时间复杂度:,最坏情况矩阵是全 1 矩阵,可能没有被卡吧
- 空间复杂度:,
方法二:预处理行前缀和
思路
先预处理矩阵所有行的前缀和,比如这个网格,预处理后就变成这样了
比如第一行一共可以数出 1 + 2 + 3 = 6 个矩阵;然后我们以某一个点 (a, b) 为右下角,不断缩短行数来计算出第 a 行上面矩阵的个数。其实这个大矩阵中小矩阵的数也可以推导出来,比如,设 n 为某一个大矩阵内部的 1 × 1 的小矩阵数,则有 比如某一个矩阵由 3 个小矩阵组成,那么一共可以组合出 6 个子矩阵,上式也等价于:所以我们累加每一行的前缀和的数值,也可以得到正确结果
class Solution {
public:
int numSubmat(vector<vector<int>>& g) {
int n = g.size(), m = g[0].size(), cnt = 0;
vector<vector<int>> s(n+1, vector<int>(m+1));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
s[i][j] = g[i-1][j-1] == 0 ? 0 : s[i][j-1] + 1;
if (g[i-1][j-1] == 1) {
int mi = INT_MAX;
for (int k = i; k >= 0; k--) {
mi = min(mi, s[k][j]);
if (mi == 0) //代表该右下角存在0
break;
cnt += mi;
}
}
}
return cnt;
}
};
复杂度分析
- 时间复杂度:,
- 空间复杂度:,
可能还有更优的 的单调栈解法,id = 90258312