LeetCode 221. Maximal Square (最大正方形)

原题

Given a 2D binary matrix filled with 0’s and 1’s, find the largest square containing only 1’s and return its area.

Example:

Input: 

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

Output: 4

Reference Answer

思路分析

有两种方法,第一种就是对矩阵的每个位置求左上角以上所有元素的和,然后用所有可能构成的正方形的区域内进行面积计算,如果面积等于正方形边长的平方,说明是一个正方形,然后求最大面积。

第二种方法使用DP。设这个DP[i][j]数组为以i, j位置为右下角顶点的能够成的最大正方形的边长。数组如果是第一行或者第一列,显然dp和matrix相等。如果是其他位置,当matrix[i][j] = 1时,能够成的正方形等于左边、上边、左上能够成的正方形边长的最小值+1.为什么是最小值?因为只要存在一个0,那么就没法构成更大的正方形,这个是很保守的策略。

递推公式如下:

  • dp[0][j] = matrix[0][j] (topmost row);
  • dp[i][0] = matrix[i][0] (leftmost column);
  • For i > 0 and j > 0: if matrix[i][j] = 0, dp[i][j] = 0; if matrix[i][j] = 1, dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1.

LeetCode 221. Maximal Square (最大正方形)_第1张图片
时间复杂度是O(N2),空间复杂度是O(N2)。

这道题开始想成用相成了依据LeetCode 200 求岛屿数量的回溯法求解了,在求解过程中,回溯策略采用从左上角开始,当发现元素为1之后,当 if row < len(matrix) - 1 and col < len(matrix[0]) - 1 and matrix[row + 1][col + 1] == '1' and matrix[row + 1][ col] == '1' and matrix[row][col + 1] == '1' 进行判定,回溯return self.dfs(matrix, row + 1, col + 1) + 1;结果证明,这种方法不能判别:

Input: 
0 0 0 1
1 1 0 1
1 1 1 1
0 1 1 1
0 1 1 1
Output: 16 (实际应该为9)

错误原因正是row = 1, col =1,也满足回溯条件,故而出错。最后看参考答案,这道题采用动态规划更容易做。(吃了没判定好使用动态规划与回溯的亏)

Input:
111
010
111
Output: 1(却被程序判别为2,因为把左下角当做一个独立岛屿看待了)

而当先对左上角、左下角与右上角进行设置后,依旧不满足,因为存在

Input:
11
Output: 1(却被程序判别为2,因为把右上角当做一个独立岛屿看待了)

最后,放弃动态规划,改用DFS。

Code

class Solution(object):
    def maximalSquare(self, matrix):
        """
        :type matrix: List[List[str]]
        :rtype: int
        """
        if not matrix: return 0
        M = len(matrix)
        N = len(matrix[0])
        dp = [[0] * N for _ in range(M)]
        for i in range(M):
            dp[i][0] = int(matrix[i][0])
        for j in range(N):
            dp[0][j] = int(matrix[0][j])
        for i in range(1, M):
            for j in range(1, N):
                if int(matrix[i][j]) == 1:
                    dp[i][j] = min(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) + 1
        return max(map(max, dp)) ** 2

补充一个 C++ 版:

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if (matrix.empty() || matrix[0].empty()){
            return 0;
        }
        int m = matrix.size();
        int n = matrix[0].size();
        vector<vector<int>> dp(m, vector<int>(n, 0));
        int key = 0;
        for (int i = 0; i < m; i++){
            dp[i][0] = matrix[i][0] - '0';
            key = max(key, dp[i][0]);
        }
        for (int j = 0; j < n; j++){
            dp[0][j] = matrix[0][j] - '0';
            key = max(key, dp[0][j]);
        }
      
        for (int i = 1; i < m; i++){
            for (int j = 1; j < n; j++){
                if (matrix[i][j] == '0'){
                    dp[i][j] = 0;
                }
                else {
                    dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}) + 1;
                    key = max(key, dp[i][j]);
                }
 
            }
        }
        return key * key;
        
        
    }
};

Note:

  • 动态规划与DFS到底用哪个要仔细琢磨清楚!
  • max(map(max, dp))的使用,因为max函数无法直接作用到矩阵 dp 上,通过一个 map 映射,将max函数映射到dp元素上,得到一个迭代对象,再外套一个max函数,得到矩阵的最大值,使用方法很巧妙,值得借鉴(也可采用np.max()函数进行直接矩阵最大值求解)。

参考资料

[1] https://blog.csdn.net/fuxuemingzhu/article/details/82992233

你可能感兴趣的:(LeetCode 221. Maximal Square (最大正方形))