【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/

原文地址:https://www.cnblogs.com/flix/p/13485287.html