最大正方形

144 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

一、题目

LeetCode 最大正方形

二、题解

在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。

示例 1:

输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:4

示例 2:

输入:matrix = [["0","1"],["1","0"]]
输出:1

示例 3:

输入:matrix = [["0"]]
输出:0

方法一

我们可以直接遍历矩阵的元素,找到所有值为1的元素,然后以该值为1的元素为起点往外延伸找找一个正方形,即将该元素作为一个可能的正方形的左上角,根据这个左上角往下和右移动,每次加1个元素的大小,判断其之后的行元素以及列元素是否都为1,这样可以找到一个正方形的长度,最后就保留最大的正方形长度,正方形大小就是长度的平方了。具体的遍历矩阵元素,如果当前元素值为1的话,就可以寻找可能的最大正方形,但是需要注意不要越界,如果元素都是1那么就更新最大边长的值,最后遍历结束返回最大边长的平方即可。

方法二

或者可以考虑使用动态规划,定义与矩阵matrix相同大小的二维数组dpdp[i][j]表示以[i][j]为右下角的正方形最大边长,同时需要一个变量maxSide记录最大的边长。那么对于矩阵的第一行元素,如果其值为1,那么就初始化dp对应位置的值为1,同时更新最大边长maxSide;同样的对与第一列的元素,如果其值为1,那么也将dp对于位置的值设置为1,同时更新最大边长maxSide的值。对于其他位置的元素如果值为1的话,以[i][j]为右下角的正方形而言的最大边长为左边、左上角、上边三个位置的正方形中最小的一个边长加上当前位置+1,同时更新最大边长。最后只需返回最大边长的一个平方。

三、代码

方法一 Java代码

class Solution {
    public int maximalSquare(char[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        int maxSide = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '1') {
                    maxSide = Math.max(maxSide, 1);
                    int border = Math.min(m - i, n - j);
                    se:
                    for (int k = 1; k < border; k++) {
                        for (int l = 0; l <= k; l++) {
                            if (matrix[i + k][j + l] == '0' || matrix[i + l][j + k] == '0') {
                                break se;
                            }
                        }
                        maxSide = Math.max(maxSide, k + 1);
                    }
                }
            }
        }
        return maxSide * maxSide;
    }
}

时间复杂度:O(n^4),首先需要遍历二维数组的每一个元素,然后如果元素值为1则继续以该元素为起点遍历其周围元素。

空间复杂度:O(1),只需常数空间。


方法二 Java代码

class Solution {
    public int maximalSquare(char[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        int maxSide = 0;

        int[][] dp = new int[m][n];
        for (int i = 0; i < m; i++) {
            if (matrix[i][0] == '1') {
                dp[i][0] = 1;
                maxSide = Math.max(maxSide, dp[i][0]);
            }
        }
        for (int i = 0; i < n; i++) {
            if (matrix[0][i] == '1') {
                dp[0][i] = 1;
                maxSide = Math.max(maxSide, dp[0][i]);
            }
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (matrix[i][j] == '1') {
                    dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
                }
                maxSide = Math.max(maxSide, dp[i][j]);
            }
        }
        return maxSide * maxSide;
    }
}

时间复杂度:O(n^2),需要遍历一次矩阵的所有元素

空间复杂度:O(n^2),使用了与矩阵同等大小的dp数组。