开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 17 天,点击查看活动详情
1139. 最大的以 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 <= 1001 <= grid[0].length <= 100grid[i][j]为0或1
思路
虽然说数据量很小,但是如果靠纯暴力的遍历会非常的耗时,题目要求的是边界为1的正方形,我们可以转换一下思路,如果用大的正方形减去小的正方形,得到的就是一圈边界的和,这样就间接地求得了正方形的边界。
对于正方形的求和,我们可以使用二维的前缀和来求解,我们先求得每一个从(0,0)点开始,到每一个位置的和,具体的细节就不再一一赘述,求得前缀和之后,我们就可以计算每个正方形的面积了。
对于每个位置的正方形来说,我们可以先由最大的长度开始遍历,若符合了条件,则无需再尝试更小长度的正方形。若起始点的元素值为0,我们也没有必要再进行遍历计算。
题解
class Solution {
public int largest1BorderedSquare(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] preSum = new int[m + 1][n + 1];
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
preSum[i + 1][j + 1] = preSum[i + 1][j] + preSum[i][j + 1] - preSum[i][j] + grid[i][j];
}
}
int ans = 0;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(grid[i][j] == 0) {
continue;
}
for(int len = Math.min(m - i, n - j); len > 0; len--) {
int out = preSum[i + len][j + len] - preSum[i + len][j] - preSum[i][j + len] + preSum[i][j];
int inner = preSum[i + len - 1][j + len - 1] - preSum[i + len - 1][j + 1] - preSum[i + 1][j + len - 1] + preSum[i + 1][j + 1];
if(out - inner == 4 * len - 4) {
ans = Math.max(ans, len * len);
break;
}
}
}
}
return ans;
}
}
如果你有其他的思路或者更好的解法,亦或者你发现了文章出现了错误或有不足,欢迎在评论区和我交流,我看到了一定会回复。
写文章不易,如果你觉得文章对你有帮助,麻烦点一下点赞、收藏,你的支持是我写文章的最大动力!