最大正方形

标签: 数组 动态规划 矩阵

难度: Medium

在一个由 '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

 

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 300
  • matrix[i][j]'0''1'

Submission

运行时间: 99 ms

内存: 30.3 MB

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        """
        dp数组含义:
        dp[i][j]代表着,i,j处所能构成最大正方形的最大边长
        递推公式:
            if matrix[i][j] == '1':
                dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1])+1
        初始化:
            第0行和第0列值为1需要进行初始化为1
        遍历顺序:
            从左到右,从上到下,正序
        """
        m = len(matrix)
        n = len(matrix[0])
        if m == n == 0:
            return 0

        dp = [[0] * n for _ in range(m)]
        for i in range(m):
            if matrix[i][0] == "1":
                dp[i][0] = 1
        for j in range(n):
            if matrix[0][j] == "1":
                dp[0][j] = 1

        for i in range(1, m):
            for j in range(1, n):
                if matrix[i][j] == "1":
                    dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1
        # print(dp)
        return max([max(i) for i in dp]) ** 2

Explain

这道题使用动态规划来解决。定义二维dp数组,其中dp[i][j]表示以(i,j)为右下角的正方形的最大边长。状态转移方程为:当前位置如果为'1',则dp[i][j] = min(左上角dp值, 正上方dp值, 正左方dp值) + 1。最后返回dp数组中的最大值的平方即为最大正方形面积。

时间复杂度: O(mn)

空间复杂度: O(mn)

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        """
        dp数组含义:
        dp[i][j]代表着,i,j处所能构成最大正方形的最大边长
        递推公式:
            if matrix[i][j] == '1':
                dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1])+1
        初始化:
            第0行和第0列值为1需要进行初始化为1
        遍历顺序:
            从左到右,从上到下,正序
        """
        m = len(matrix)
        n = len(matrix[0])
        if m == n == 0:
            return 0
        
        # 初始化dp数组
        dp = [[0] * n for _ in range(m)]
        
        # 初始化第0行和第0列
        for i in range(m):
            if matrix[i][0] == "1":
                dp[i][0] = 1
        for j in range(n):
            if matrix[0][j] == "1":
                dp[0][j] = 1
        
        # 遍历填充dp数组
        for i in range(1, m):
            for j in range(1, n):
                if matrix[i][j] == "1":
                    dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1
                    
        # 返回dp数组中最大值的平方
        return max([max(i) for i in dp]) ** 2

Explore

在动态规划中,取min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1的目的是确保在(i, j)位置能形成一个正方形。dp[i][j]的最大值取决于它的上方、左方和左上方三个相邻位置的dp值。只有当这三个位置都能至少构成一个边长为k的正方形时,(i, j)位置才可能构成一个边长为k+1的正方形。因此,取这三个值的最小值确保了不会超出任何一个方向能提供的正方形边长,这是形成一个更大正方形的必要条件。

初始化第0行和第0列的方法仍然适用,因为在初始化时,我们根据矩阵中相应位置的值('1'或'0')来设置dp数组的值。如果第一行或第一列的值为'0',对应的dp值将被初始化为0,反映了在这些位置无法形成任何正方形。这种初始化方式确保了dp数组正确地表示了每个位置的最大正方形边长。

为了确保空矩阵输入不会导致错误,可以在动态规划算法开始之前加入一个检查,确保矩阵不为空。具体来说,可以在计算m和n(矩阵的行和列数)之后,立即检查它们是否为0。如果m或n为0,函数直接返回0,表示没有任何正方形可以形成。这个检查可以有效防止后续代码在访问空矩阵时出错。

双层循环遍历整个矩阵的方法能够处理包括矩阵全为'1'或全为'0'的所有边界情况。当矩阵全为'1'时,dp数组将正确计算出每个位置的最大正方形边长,最终返回整个矩阵能形成的最大正方形面积。当矩阵全为'0'时,dp数组中的所有值将保持为0,函数最终返回0。因此,这种遍历方法确保了算法能在所有可能的矩阵情况下正确运行。