每日一题——最大的以 1 为边界的正方形

168 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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 <= 100
  • 1 <= grid[0].length <= 100
  • grid[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;
    }
}

如果你有其他的思路或者更好的解法,亦或者你发现了文章出现了错误或有不足,欢迎在评论区和我交流,我看到了一定会回复。

写文章不易,如果你觉得文章对你有帮助,麻烦点一下点赞、收藏,你的支持是我写文章的最大动力!