一、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