leetcode 1139. 最大的以 1 为边界的正方形

30 阅读1分钟

1. 题目与解析

给你一个由若干 0 和 1 组成的二维网格 grid,请你找出边界全部由 1 组成的最大 正方形 子网格,并返回该子网格中的元素数量。如果不存在,则返回 0

输入: grid = [[1,1,1],[1,0,1],[1,1,1]]

输出: 9

输入: grid = [[1,1,0,0]]

输出: 1

  • 1 <= grid.length <= 100
  • 1 <= grid[0].length <= 100
  • grid[i][j] 为 0 或 1

题意很简单,但是往往,越简单的题目表述越容易让人一头雾水,找不到解题的关键。

为了找到解题的思路,我们就需要梳理何种条件下,我们可以计算出题目的答案。

对于一个点(i,j),我们将其视为一个正方形的点,在判断其是否可以组成正方形时,我们需要做的是判断能不能形成四条对应的边.

首先(i,j)为0时,肯定不可以为1时,其存在横线与纵向两条边,这两条边的最小值就可以作为边长d。

有了一个点以及边长,我们就可以确定其横向与纵向相邻的两个点(i+d,j),(i,j+d)。

之后,再通过相邻的两个点与对角线上的点(i+d,j+d)判断另外的两条边是否存在即可。

思路确定了,判断边存不存在就是判断两点之间是否都为1,这个过程会存在重复计数的情况,为了避免这一问题的发生,我们可以借助一个二维的dp表格,用动态规划的方式,分别统计横向与纵向相邻的1的个数,之后用之前提到的判断逻辑进行计算解题即可。

2. 题解

public int largest1BorderedSquare(int[][] grid) {
    int m = grid.length;
    int n = grid[0].length;
    int[][][] dp = new int[m+1][n+1][2];
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (grid[i-1][j-1] == 1){
                dp[i][j][0] = 1 + dp[i][j-1][0];
                dp[i][j][1] = 1 + dp[i-1][j][1];
            }
        }
    }
    int res = 0;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            for (int side = Math.min(dp[i][j][0], dp[i][j][1]); side >= 1; side--){
                if (dp[i][j-side+1][1] >= side && dp[i-side+1][j][0] >= side){
                    res = Math.max(res, side);
                    break;
                }
            }
        }
    }
    return res * res;
}