🚩传送门:牛客题目
力扣题目

题目

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

示例 1:
image.png

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

解题思路:动态规划

👉 定义:[NC]108. 最大正方形 - 图2 表示以 [NC]108. 最大正方形 - 图3 为右下角,且只包含 [NC]108. 最大正方形 - 图4 的正方形的边长最大值。

如果我们能计算出所有 [NC]108. 最大正方形 - 图5的值,那么其中的最大值即为矩阵中只包含 [NC]108. 最大正方形 - 图6 的正方形的边长最大值,其平方即为最大正方形的面积。

那么如何计算 [NC]108. 最大正方形 - 图7 中的每个元素值呢?对于每个位置[NC]108. 最大正方形 - 图8 ,检查在矩阵中该位置的值:

  • 如果该位置的值是 [NC]108. 最大正方形 - 图9,则 [NC]108. 最大正方形 - 图10 ,因为当前位置不可能在由 [NC]108. 最大正方形 - 图11 组成的正方形中;

  • 如果该位置的值是 [NC]108. 最大正方形 - 图12,则 [NC]108. 最大正方形 - 图13的值由其上方、左方左上方的三个相邻位置的 [NC]108. 最大正方形 - 图14 值决定。

状态转移方程:具体而言,当前位置的元素值等于三个相邻位置的元素中的最小值加 [NC]108. 最大正方形 - 图15

[NC]108. 最大正方形 - 图16

此外,还需要考虑边界条件。如果 [NC]108. 最大正方形 - 图17[NC]108. 最大正方形 - 图18 中至少有一个为 [NC]108. 最大正方形 - 图19 ,则以位置[NC]108. 最大正方形 - 图20 为右下角的最大正方形的边长只能是 [NC]108. 最大正方形 - 图21 ,因此 [NC]108. 最大正方形 - 图22

以下用一个例子具体说明。原始矩阵如下。

  1. 0 1 1 1 0
  2. 1 1 1 1 0
  3. 0 1 1 1 1
  4. 0 1 1 1 1
  5. 0 0 1 1 1

对应的 [NC]108. 最大正方形 - 图23 值如下。

  1. 0 1 1 1 0
  2. 1 1 2 2 0
  3. 0 1 2 3 1
  4. 0 1 2 3 2
  5. 0 0 1 2 3

下图也给出了计算 [NC]108. 最大正方形 - 图24值的过程。
221_fig1.png

复杂度分析

时间复杂度:[NC]108. 最大正方形 - 图26,其中 [NC]108. 最大正方形 - 图27[NC]108. 最大正方形 - 图28 是矩阵的行数和列数,需要遍历原始矩阵中的每个元素计算 [NC]108. 最大正方形 - 图29的值。

空间复杂度:[NC]108. 最大正方形 - 图30,其中 [NC]108. 最大正方形 - 图31[NC]108. 最大正方形 - 图32 是矩阵的行数和列数 。

  1. - 创建了一个和原始矩阵大小相同的矩阵 ![](https://cdn.nlark.com/yuque/__latex/32ed5e9e580d123173ac55ad90458209.svg#card=math&code=dp&id=S47gf)。由于状态转移方程中的 ![](https://cdn.nlark.com/yuque/__latex/7cc22f166a48346fa068c82b59d72be5.svg#card=math&code=dp%5Bi%5D%5Bj%5D&id=KmG6s)由其上方、左方和左上方的三个相邻位置的 ![](https://cdn.nlark.com/yuque/__latex/32ed5e9e580d123173ac55ad90458209.svg#card=math&code=dp&id=GSFJR)值决定,因此可以使用两个一维数组进行状态转移,空间复杂度优化至 ![](https://cdn.nlark.com/yuque/__latex/e65a67ac353abeeff44c359310d05c02.svg#card=math&code=O%28n%29&id=V9ciE)。

官方代码

class Solution {
    public int maximalSquare(char[][] matrix) {
        int maxSide = 0;
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return maxSide;
        }
        int rows = matrix.length, columns = matrix[0].length;
        int[][] dp = new int[rows][columns];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                if (matrix[i][j] == '1') {
                    if (i == 0 || j == 0) {
                        dp[i][j] = 1;
                    } else {
                        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]);
                }
            }
        }
        int maxSquare = maxSide * maxSide;
        return maxSquare;
    }
}