动态规划 dp解 最大正方形

题目来源:LeetCode第1139题
难度:中等
题目描述:
给你一个由若干0和1组成的二维网格grid,请你找出边界全部由1组成的最大正方形子网格,并返回该子网格中的元素数量。如果不存在,则返回0。

示例 1:
输入:grid = [
[1,1,1],
[1,0,1],
[1,1,1]]
输出:9

示例 2:
输入:grid = [[1,1,0,0]]
输出:1

提示:
1<=grid.length<=100
1<=grid[0].length<=100
grid[i][j]为0或1

只要搞懂动态规划的原理,代码就非常简洁。而这题只要正方形4条边的网格都是1即可,中间是什么数字不用管

解题思路是这样的:

1.先计算每个网格(i,j)的左边和上边连续1的个数。

2.遍历二维网格,以每一个格子(i,j)为正方形的右下角,分别找出这个(i,j)格子上边的格子和左边的格子连续1的个数,取最小值作为正方形的边长cursize,然后判断此时以cursize为边长的正方形的左边长和上边长是否都大于等于正方形边长,如果都大于等于正方形边长说明符合正方形条件,可以更新maxsize,否则缩小正方形的边长,继续判断……。

定义一个三维数组,用来记录格子(i,j)左边连续1个数和上边连续1个数。
dp[i][j][0]: (i,j)左边连续1的个数
dp[i][j][1]: (i,j)上边连续1的个数

在这里插入图片描述
分别沿着左边和上边找出他们连续1的个数,最小的作为正方形的边长。因为左边和上边连续1的个数我们在第一步的时候已经计算过,分别是dp[i][j][0]和dp[i][j][1],也就是正方形的边长我们暂时可以认为是

 cursize = Math.min(dp[i][j][0], dp[i][j][1]);

确定好初始的正方形边长后,我们还需要验证这个正方形的左边和上边是否符合,如果符合,则更新maxsize,否则就缩小正方形边长,继续寻找符合的情况。
在这里插入图片描述
这种情况上边和左边的长度均大于cursize = 3 ,所以更新maxsize

在这里插入图片描述
这种情况正方形的上边不是连续1,不符合正方形条件。缩小正方形边长,继续寻找。

贴代码:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

int Grid[100][100];   //给定的2维网格  
int dp[101][101][2];
//dp[i][j][0]: (i,j)横向连续1的个数   这里的(i,j)指的是第i,j个格子   对应下标+1 
//dp[i][j][1]: (i,j)竖向连续1的个数
int maxsize = 0;  //全局变量,统计所有正方形的最大边长 

int Min(int x,int y)
{
	return x>y?y:x;
}

int GetSquare_size(int grid[100][100],int m,int n){
	
	int i,j;
	
	//以每个格子为正方形的右下角,计算这个格子左边和上边的连续1的个数 
	for(i=1;i<=m;i++)
	{
		for(j=1;j<=n;j++)
		{
			if(grid[i-1][j-1]==0)	// 0不计入边长 
				continue;
			
			else if(grid[i-1][j-1]==1)
			{
				dp[i][j][0] = dp[i][j-1][0] + 1;
				dp[i][j][1] = dp[i-1][j][1] + 1;	
			}				
		}	
	}
	int cursize = 0;
	
	for(i=1;i<=m;i++)   //维持maxsize变量  动态更新正方形的最大长度 
	{
		for(j=1;j<=n;j++)
		{
			cursize =  Min(dp[i][j][0],dp[i][j][1]);  //以(i,j)为右下角的正方形的初始边长 
							//判断此时正方形的左下角格子的竖向边长 和 右上角的格子的横向边长是否都大于cursize 
							//若均大于  cursize即为一个满足的正方形边长 
			while(cursize)
			{
				if(dp[i][j-cursize+1][1]>=cursize && dp[i-cursize+1][j][0]>=cursize) //符合正方形条件 
				{
					if(cursize >= maxsize)
						maxsize = cursize;
						
					break;	  //
				}
				cursize --; //若不符合正方形条件,说明边长cursize的正方形有条边不是连续1 则缩小cursize 继续判断	
			}		
		}	
	}	
	
	return maxsize;
}
int main()
{
	int m,n;
	int i,j;
	
	scanf("%d %d",&m,&n);   //m*n的二维网格 
	
	for(i=0;i<m;i++)
		for(j=0;j<n;j++)
			scanf("%d",&Grid[i][j]);					
	
	int Square_size = GetSquare_size(Grid,m,n); 
	printf("The square area is%d",Square_size*Square_size);
	
	return 0;
}

结果展示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值