题目描述
在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。
示例:
输入:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
输出: 4
解法一:动态规划
图 1:受限于左上的 0
图 2:受限于上边的 0
图 3:受限于左边的 0
数字表示:以此为正方形右下角的最大边长
黄色表示:格子 ? 作为右下角的正方形区域
状态方程:
if (grid[i - 1][j - 1] == '1') {
dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1;
}
class Solution {
public int maximalSquare(char[][] matrix) {
int n=matrix.length;
if(n==0) return 0;
int m=matrix[0].length;
//初始化最左最上为0
int[][] dp = new int[n+1][m+1];
int maxSide=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(matrix[i][j]=='1'){
//左、上、左上三者最小值
dp[i+1][j+1]=Math.min(dp[i][j],Math.min(dp[i][j+1],dp[i+1][j]))+1;
maxSide=Math.max(maxSide,dp[i+1][j+1]);
}
}
}
return maxSide*maxSide;
}
}
空间优化(降维)
class Solution {
public int maximalSquare(char[][] matrix) {
int n=matrix.length;
if(n==0) return 0;
int m=matrix[0].length;
//初始化最左最上为0
int[] dp = new int[m+1];
int maxSide=0;
for(char[] chars:matrix){
int northwest=0;
for(int j=0;j<m;j++){
int nextNorthwest=dp[j+1];
if(chars[j]=='1'){
//左、上、左上三者最小值
dp[j+1]=Math.min(northwest,Math.min(dp[j+1],dp[j]))+1;
maxSide=Math.max(maxSide,dp[j+1]);
} else{
//如果该节点字符为0,则应该清空之前的值
dp[j + 1] = 0;
}
//更新左上角值
northwest = nextNorthwest;
}
}
return maxSide*maxSide;
}
}
解法二:广搜(解法低效,代码较长可以忽略)
1.制作测试集
1.逐个坐标找到节点为1,
2.对其制作测试坐标dx、dy,将测试坐标逐个带入验证,
- 若都符合,则当前边长为k+1的正方形符合条件,计算该正方形面积。
- 若出错,则停止本轮测试,返回步骤1。
3.返回最大值
class Solution {
int[] dx;
int[] dy;
public int maximalSquare(char[][] matrix) {
int n=matrix.length;
if(n==0) return 0;
int m=matrix[0].length;
int max=0;
boolean flag;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(matrix[i][j]=='1'){
//存在一个为1,则max可以置为1
max=Math.max(max,1);
//标记赋true
flag=true;
//调了半天发现m写成了n,有些情况无法进入for循环
for(int k=1;k<=n-i&&k<=m-j;k++){
//制作测试集
setMatrix(matrix,k);
//逐个尝试测试集中的数据
for(int c=0;c<2*k+1;c++){
int x=i+dx[c];
int y=j+dy[c];
//测试集有一个数据不符合,则标记出错
if(x>=n||y>=m||matrix[x][y]=='0'){
flag=false;
break;
}
}
//若出错,则结束该位置的测试
if(!flag){
break;
}
//没有出错,计算当前正方形的面积
else{
max=Math.max(max,(k+1)*(k+1));
}
}
}
}
}
return max;
}
public void setMatrix(char[][] matrix,int k){
dx=new int[2*k+1];
dy=new int[2*k+1];
//填充k
Arrays.fill(dx,k);
Arrays.fill(dy,k);
//正序0-k
for(int i=0;i<=k;i++){
dx[i]=i;
}
//倒序0-k
for(int i=2*k;i>k;i--){
dy[i]=2*k-i;
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZOmHIgfV-1595752781928)(D:\leetcode\题目\矩阵\221.最大正方形.assets\image-20200725184411039.png)]
2.两节点广搜
class Solution {
public int maximalSquare(char[][] matrix) {
int n=matrix.length;
if(n==0) return 0;
int m=matrix[0].length;
int max=0;
boolean flag;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(matrix[i][j]=='1'){
//存在一个为1,则max可以置为1
max=Math.max(max,1);
flag=true;
for(int k=1;k<n-i&&k<m-j;k++){
int x=i+k;
int y=j+k;
if(matrix[x][y]=='0'){
break;
}
for(int c=1;c<=k;c++){
int[] dx={-c,0};
int[] dy={0,-c};
for(int z=0;z<2;z++){
int x1=x+dx[z];
int y1=y+dy[z];
if(matrix[x1][y1]=='0'){
flag=false;
break;
}
}
if(!flag){
break;
}
}
if(!flag){
break;
}
else{
max=Math.max(max,(k+1)*(k+1));
}
}
}
}
}
return max;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N5h139Yu-1595752781930)(D:\leetcode\题目\矩阵\221.最大正方形.assets\image-20200725184219366.png)]