1. 问题描述:
在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。
示例:
输入:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
输出: 4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximal-square
2. 思路分析:
① 首先是可以使用暴力来破解的,一开始的是想到使用四层循环来写,但是循环太多绕晕了,有点混乱,于是看了一下官方的题解,发现暴力破解可以使用如下的思路:
首先是遍历二维数组,发现是1的话那么是可能构成更大的正方形的,先是尝试长度为2的正方形,以当前的位置的1对应的下一行是否全部满足条件,以当前位置的1的右边的列是否满足条件这样的话检测下一行与右边的列就可以知道长度为2的正方形是否满足条件,最外层可以使用一个循环来扩展正方形,表示当前的边长是几的正方形,这里可以设置一个标志当发现存在0的时候说明当前的长度是不可以构成正方形,下面的是检查正方形扩展是否满足条件的示意图:
② 除了使用暴力破解的方法之外,还可以动态规划的方法,思路是对于当前位置是1的情况下形成的最大正方形需要受到上边,左边、左上角的位置的正方形的数量的约束,所以需要取出其中的最小值才可以表示以当前位置形成的最大正方形是多少,可以参考一下力扣的题解,里面对应的图片这样对于动态规划比较好理解一点,感觉需要多做与多看一些动态规划的题目才会有思路,并且需要结合图形具体分析一下从而得到dp数组,主要是证明:
f(i, j) <= min{f(i - 1, j) + 1, f(i - 1, j - 1) + 1, f(i, j - 1) + 1}
f(i, j) >= min{f(i - 1, j) + 1, f(i - 1, j - 1) + 1, f(i, j - 1) + 1}
通过反证法证明:f(i, j) < min{f(i - 1, j) + 1, f(i - 1, j - 1) + 1, f(i, j - 1) + 1}存在矛盾所以f(i, j) >= min{f(i - 1, j) + 1, f(i - 1, j - 1) + 1, f(i, j - 1) + 1}成立,综合两个式子可以得到f(i, j) = min{f(i - 1, j) + 1, f(i - 1, j - 1) + 1, f(i, j - 1) + 1}
3. 代码如下:
暴力破解代码:
import java.util.Scanner;
public class Solution {
public int maximalSquare(char[][] matrix) {
int r = matrix.length, c = r > 0 ? matrix[0].length : 0;
int max = 0;
for (int i = 0; i < r; ++i){
for (int j = 0; j < c; ++j){
if (matrix[i][j] == '1'){
int curLen = 1;
int f = 1;
while (i + curLen < r && j + curLen < c && f == 1){
for (int k = j; k <= j + curLen; ++k){
if (matrix[i + curLen][k] == '0'){
f = 0;
break;
}
}
/*检查列*/
for (int l = i; l <= i + curLen; ++l){
if (matrix[l][j + curLen] == '0'){
f = 0;
break;
}
}
if (f == 1){
curLen++;
}
}
max = Math.max(max, curLen);
}
}
}
return max * max;
}
}
官方动态规划代码:
import java.util.Scanner;
public class Solution {
public int maximalSquare(char[][] matrix) {
int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0;
int[][] dp = new int[rows + 1][cols + 1];
int maxsqlen = 0;
for (int i = 1; i <= rows; i++) {
for (int j = 1; j <= cols; j++) {
# dp[i][j]表示以当前(i, j)位置的最大正方形的边长
if (matrix[i-1][j-1] == '1'){
dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
maxsqlen = Math.max(maxsqlen, dp[i][j]);
}
}
}
return maxsqlen * maxsqlen;
}
}
python代码:
from typing import List
class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
r, c = len(matrix), len(matrix[0])
if r == 0 or c == 0: return 0
dp = [[0] * (c + 1) for i in range(r + 1)]
res = 0
for i in range(1, r + 1):
for j in range(1, c + 1):
if matrix[i - 1][j - 1] == "1":
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
res = max(res, dp[i][j])
return res * res