leetcode第196场周赛
1504. 统计全 1 子矩形
给你一个只包含 0 和 1 的 rows * columns 矩阵 mat ,请你返回有多少个 子矩形 的元素全部都是 1 。
示例 1:
输入:mat = [[1,0,1],
[1,1,0],
[1,1,0]]
输出:13
解释:
有 6 个 1x1 的矩形。
有 2 个 1x2 的矩形。
有 3 个 2x1 的矩形。
有 1 个 2x2 的矩形。
有 1 个 3x1 的矩形。
矩形数目总共 = 6 + 2 + 3 + 1 + 1 = 13 。
示例 2:
输入:mat = [[0,1,1,0],
[0,1,1,1],
[1,1,1,0]]
输出:24
解释:
有 8 个 1x1 的子矩形。
有 5 个 1x2 的子矩形。
有 2 个 1x3 的子矩形。
有 4 个 2x1 的子矩形。
有 2 个 2x2 的子矩形。
有 2 个 3x1 的子矩形。
有 1 个 3x2 的子矩形。
矩形数目总共 = 8 + 5 + 2 + 4 + 2 + 2 + 1 = 24 。
示例 3:
输入:mat = [[1,1,1,1,1,1]]
输出:21
示例 4:
输入:mat = [[1,0,1],[0,1,0],[1,0,1]]
输出:5
提示:
1 <= rows <= 150
1 <= columns <= 150
0 <= mat[i][j] <= 1
算法1 暴力枚举 + check O(n^6)
思路
先枚举矩阵上下两边,再枚举矩阵左右两边,check,不满足条件就break,满足条件sum++。(稍微优化一下就是二维前缀和判断全1)
本蒟蒻还是太菜,比赛的时候只会用最暴力的方法,连二维前缀和都没有想到,n^6铁定超时。。。
class Solution {
public:
int numSubmat(vector<vector<int>>& mat) {
int n = mat.size(), m = mat[0].size();
int sum = 0;
for(int i = 0; i < n; i ++){
for(int j = i; j < n; j ++){
for(int l = 0; l < m; l ++){
for(int r = l; r < m; r ++){
bool flag = true;
for(int p = i; p <= j; p ++){
for(int q = l; q <= r; q ++){
if(mat[p][q] == 0){
flag = false;
break;
}
if(!flag) break;
}
}
if(flag) sum ++;
}
}
}
}
return sum;
}
};
算法2 枚举上下边界,二维压成一维 O(n^3)
思路
参考的b站上大佬的思路,枚举上下边界,二维压成一维 是常用的套路,类似的题可以做做面试题 17.24. 最大子矩阵
枚举上下边界i和j,二维压成一维,sum[k]记录当前列k的总和,sum[k]=i-j+1说明列k全1,连续cnt次列全1给ans贡献1+2+...+cnt。为什么呢,举个列子:矩阵[[1,1,1]]有三次列连续列全1,所以有1+2+3个全一子矩阵。
class Solution {
public:
int numSubmat(vector<vector<int>>& mat) {
int n = mat.size(), m = mat[0].size();
vector<int> sum(m, 0);
int ans = 0;
for(int i = 0; i < n; i ++){
for(int k = 0; k < m; k ++) sum[k] = 0;
for(int j = i; j < n; j ++){
for(int k = 0; k < m; k ++) sum[k] += mat[j][k];
int cur = j - i + 1, cnt = 0;
for(int k = 0; k < m; k ++){
if(sum[k] == cur){
cnt ++;
ans += cnt;
}
else cnt = 0;
}
}
}
return ans;
}
};
算法3 dp O(n^3)
思路
矩阵里每个点(i.j)统计他这行左边到他这个位置最多有几个连续的1,存为left[i]j。然后对于每个点(i.j),我们固定子矩形的右下角为(i.j),利用left从该行i向上寻找子矩阵左上角为第k行的矩阵个数。每次将子矩阵个数加到答案中即可。
class Solution {
public:
int numSubmat(vector<vector<int>>& mat) {
int n = mat.size();
int m = mat[0].size();
vector<vector<int> > left(n,vector<int>(m));
int now = 0;
for(int i=0;i<n;i++){
now = 0;
for(int j=0;j<m;j++){
if(mat[i][j] == 1) now ++;
else now = 0;
left[i][j] = now;
}
}
int ans = 0,minx;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
minx = 0x3f3f3f3f;
for(int k=i;k>=0;k--){
minx = min(left[k][j],minx);//向上找到最短连续的1个数,要组成全1矩阵,类似于木桶原理,取决于最短边
ans += minx;
}
}
}
return ans;
}
};
参考
作者:lin-miao-miao
链接:https://leetcode-cn.com/problems/count-submatrices-with-all-ones/solution/5454-tong-ji-quan-1-zi-ju-xing-by-lin-miao-miao/
来源:力扣(LeetCode)