LeetCode 1277.统计全为1的正方形子矩阵数量(动态规划)

题目描述

LeetCode 1277.统计全为1的正方形子矩阵数量(动态规划)_第1张图片
首先,暴力解就是以矩阵每一个点为起点,依次判断边长为1,2,3,...,min(矩阵长, 矩阵宽)的区域是否是正方形,显然复杂度是过不了。

很容易知道,上述过程在判断较大区域是否为正方形的时候,并没有用到前面计算的结果,每一次判断都从头开始。这也是复杂度过高的原因。

那么怎么利用之前判断过的结果呢?举个例子,比如我要判断以(2, 3)为右下角边长为3的正方形区域(红色边框区域)是否是全为1:

  • 先判断(i, j)位置是否为1,如果否,则显然不满足;如果是,进行下一步判断

  • 判断分别以(i - 1, j), (i - 1, j - 1), (i, j - 1)为右下角的区域是否能构成边长为2的正方形,如果能,那就满足条件。LeetCode 1277.统计全为1的正方形子矩阵数量(动态规划)_第2张图片
    基于上述,我们可以看出思路大致跟最大正方形那题差不多,设dp[i][j][k]表示以(i, j)为右下角,边长为k的正方形区域是否全为1,那么易得出如下状态转移方程:

      dp[i][j][k] = (matrix[i][j] == 1 && dp[i - 1][j][k - 1] && dp[i][j - 1][k - 1] && dp[i - 1][j - 1] [k - 1]);
    
    int countSquares(vector<vector<int>>& matrix) {
        r = matrix.size();
        c = matrix[0].size();
        int dp[r][c];
        memset(dp, 0, sizeof(dp));
        int count = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                dp[i][j][0] = (matrix[i][j] == 1);
                count += dp[i][j][0] ? 1 : 0;
            }
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                for (int k = 1; k < len; k++) {
                    dp[i][j][k] = (matrix[i][j] == 1 && dp[i - 1][j][k - 1] && dp[i][j - 1][k - 1] && dp[i - 1][j - 1] [k - 1]);
                    if (dp[i][j][k]) {
                        count++;
                    }
                }
            }
        }
        return count;
    }

优化

首先,题目并不关心边长为1,2,…,k的各有多少个,并且我们知道,以(i, j)为右下角边长为k的正方形全为1的话,那么以(i, j)为右下角边长分别为1,2,…,k - 1的正方形区域一定是全为1,如下图:
LeetCode 1277.统计全为1的正方形子矩阵数量(动态规划)_第3张图片
上图中,如果红色区域是边长为3的全1正方形区域,那么它一定包含了一个边长为2和边长为1的全1正方形区域。所以,我们只需记录以(i, j)为右下角的区域包含的最大全1正方形边长即可,这个最大边长也即以(i , j)为右下角的全1正方形的个数.
那么基于此,我们就可以将原始的dp降一维度,设dp[i][j]表示以(i, j)为右下角的最大全1正方形区域的边长,则有如下状态转移方程:

dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;

这就和最大正方形那题的状态转移方程完全一样了。

    int countSquares(vector<vector<int>>& matrix) {
        r = matrix.size();
        c = matrix[0].size();
        int ans = 0;
        int dp[r][c];
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < r; i++)
            ans += dp[i][0] = matrix[i][0];
        for(int j = 1; j < c; j++)
            ans += dp[0][j] = matrix[0][j];
        for(int i = 1; i < r; i++)
        {
            for(int j = 1; j < c; j++)
            {
                if(matrix[i][j])
                {
                    dp[i][j] = min(min(dp[i-1][j],dp[i][j-1]), dp[i-1][j-1]) + 1;
                    ans += dp[i][j];
                }
            }
        }
        return ans;
    }

时间复杂度:O(MN)
空间复杂度:O(MN)

注:本文引用自https://leetcode-cn.com/problems/count-square-submatrices-with-all-ones/solution/tong-ji-quan-wei-1-de-zheng-fang-xing-zi-ju-zhen-f/

你可能感兴趣的:(LeetCode)