1. 问题描述:
给你一个由若干 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
2. 思路分析:
① 一开始感觉这个是一个动态规划的题目(肯定是动态规划),没有啥思路,于是看了一下领扣的题解,找到一个大佬的比较好的思路,下面是我对于大佬思路的理解:
使用四个方向的二维列表来表示以当前位置的方向上的连续的1的数目,比如[[1,1,1],[1,0,1],[1,1,1]]假如当前位置为0,0,那么右边连续的1的数目就是3,下边的连续的1也是3,对于其余方向也是同样进行计算的,所以我们在一开始的时候就可以对四个方向的二维列表进行初始化,得到当前位置的四个方向上连续的1的数目,然后我们可以检查当前位置的右边连续1的数目的与下边连续的1的数目,取出两者的最小值即表示当前的右边与下边能够构成的最大边长,我们需要计算出当前位置能够构成最大边长的右下角的位置,然后看这个位置的左边与上边的能够构成的最大边长是多少,假如右下的最大边长小于等于左上的最大边长说明能够当前的边长是满足条件的,假如不满足那么需要对边长进行减1继续尝试更短一点的边长看是否满足条件
下面是题目中的例子对应的四个方向列表:
② 整个思路还是挺好理解的,对于这种动态规划的题目还是需要多思考,多总结一下才会有自己的思路,大佬题解的链接如下:https://leetcode-cn.com/problems/largest-1-bordered-square/solution/java-si-lu-jian-dan-by-noob-22/
3. 代码如下:
from typing import List
class Solution:
def largest1BorderedSquare(self, grid: List[List[int]]) -> int:
# 维护四个方向列表
row, col = len(grid), len(grid[0])
right = [[0] * col for i in range(row)]
down = [[0] * col for i in range(row)]
left = [[0] * col for i in range(row)]
up = [[0] * col for i in range(row)]
for i in range(row):
for j in range(col):
if grid[i][j] == 1:
left[i][j] = 1 if j == 0 else left[i][j - 1] + 1
up[i][j] = 1 if i == 0 else up[i - 1][j] + 1
# 从二维列表的最后一个位置开始
for i in range(row - 1, -1, -1):
for j in range(col - 1, -1, -1):
if grid[i][j] == 1:
# 类似于三目运算符
right[i][j] = 1 if j == col - 1 else right[i][j + 1] + 1
down[i][j] = 1 if i == row - 1 else down[i + 1][j] + 1
res = 0
for i in range(row):
for j in range(col):
minOne = min(right[i][j], down[i][j])
# 检查左上的边长是否小于等于右下的边长
while minOne > 0:
# 计算以当前顶点的可能构成正方形的右下角的顶点
iPoint = i + minOne - 1
jPoint = j + minOne - 1
minTwo = min(left[iPoint][jPoint], up[iPoint][jPoint])
if minOne <= minTwo:
res = max(res, min(minOne, minTwo))
break
# 左上的边长不符合要求那么边长减去1试一下
minOne -= 1
return res * res