【LeetCode-动态规划】统计全 1 子矩形
题目描述
给你一个只包含 0 和 1 的 rows * columns 矩阵 mat ,请你返回有多少个 子矩形 的元素全部都是 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 。
输入:mat = [[1,1,1,1,1,1]]
输出:21
题目链接: https://leetcode-cn.com/problems/count-submatrices-with-all-ones/
思路
使用动态规划来做。
- 状态定义:dp[i][j] 表示位置 (i, j) 左边连续 1 的个数;
- 状态转移:如果 mat[i][j]==1,则 dp[i][j] = dp[i][j-1] + 1;
这样,通过 dp[i][j] 我们就知道了从位置 (i, j) 开始往左数有多少个连续的 1。然后对于每个位置 (i, j),我们将 (i, j) 当做矩阵的右下角,然后将 j 逐渐上移直至 0,在上移的过程中,将 dp[i][j] 的最小值加入到答案中。为什么这样就可以计算矩阵的个数,可以参考这篇题解。
代码如下:
class Solution {
public:
int numSubmat(vector<vector<int>>& mat) {
if(mat.empty()) return 0;
int m = mat.size();
int n = mat[0].size();
vector<vector<int>> dp(m, vector<int>(n, 0));
for(int i=0; i<m; i++){
int cur = 1;
for(int j=0; j<n; j++){
if(mat[i][j]==1){
if(i==0 && j==0) dp[i][j] = 1;
else if(i==0) dp[i][j] = dp[i][j-1] + 1;
else if(j==0) dp[i][j] = 1;
else dp[i][j] = dp[i][j-1] + 1;
}
}
}
int ans = 0;
int minLen = INT_MAX;
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
minLen = INT_MAX;
for(int k=i; k>=0; k--){
minLen = min(minLen, dp[k][j]);
ans += minLen;
}
}
}
return ans;
}
};
- 时间复杂度:O(nnm)
n 为行数,m 为列数。 - 空间复杂度:O(nm)
参考
1、https://leetcode-cn.com/problems/count-submatrices-with-all-ones/solution/5454-tong-ji-quan-1-zi-ju-xing-by-lin-miao-miao/
2、https://leetcode-cn.com/problems/count-submatrices-with-all-ones/solution/cdong-tai-gui-hua-by-keshawn_lu/