class Solution:
def largest1BorderedSquare(self, grid):
m, n = len(grid), len(grid[0])
hor = [[0]*(n+1) for _ in range(m+1)]
ver = [[0]*(n+1) for _ in range(m+1)]
for i in range(m):
for j in range(n):
if grid[i][j]:
hor[i+1][j+1] = hor[i+1][j] + 1
ver[i+1][j+1] = ver[i][j+1] + 1
max_side = 0
for i in range(m):
for j in range(n):
small = min(hor[i+1][j+1], ver[i+1][j+1])
while small > 0:
if hor[i+2-small][j+1] >= small and ver[i+1][j+2-small] >= small:
max_side = max(max_side, small)
break
small -= 1
return max_side * max_side
class Solution {
public:
int largest1BorderedSquare(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
vector<vector<int>> hor(m+1, vector<int>(n+1, 0)), ver(m+1, vector<int>(n+1, 0));
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j]) {
hor[i+1][j+1] = hor[i+1][j] + 1;
ver[i+1][j+1] = ver[i][j+1] + 1;
}
}
}
int max_side = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
int small = min(hor[i+1][j+1], ver[i+1][j+1]);
while (small > 0) {
if (hor[i+2-small][j+1] >= small && ver[i+1][j+2-small] >= small) {
max_side = max(max_side, small);
break;
}
--small;
}
}
}
return max_side * max_side;
}
};
class Solution {
public int largest1BorderedSquare(int[][] grid) {
int m = grid.length, n = grid[0].length;
int[][] hor = new int[m+1][n+1];
int[][] ver = new int[m+1][n+1];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == 1) {
hor[i+1][j+1] = hor[i+1][j] + 1;
ver[i+1][j+1] = ver[i][j+1] + 1;
}
}
}
int maxSide = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
int small = Math.min(hor[i+1][j+1], ver[i+1][j+1]);
while (small > 0) {
if (hor[i+2-small][j+1] >= small && ver[i+1][j+2-small] >= small) {
maxSide = Math.max(maxSide, small);
break;
}
small--;
}
}
}
return maxSide * maxSide;
}
}
var largest1BorderedSquare = function(grid) {
let m = grid.length, n = grid[0].length;
let hor = Array.from({length: m+1}, () => Array(n+1).fill(0));
let ver = Array.from({length: m+1}, () => Array(n+1).fill(0));
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
if (grid[i][j]) {
hor[i+1][j+1] = hor[i+1][j] + 1;
ver[i+1][j+1] = ver[i][j+1] + 1;
}
}
}
let maxSide = 0;
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
let small = Math.min(hor[i+1][j+1], ver[i+1][j+1]);
while (small > 0) {
if (hor[i+2-small][j+1] >= small && ver[i+1][j+2-small] >= small) {
maxSide = Math.max(maxSide, small);
break;
}
small--;
}
}
}
return maxSide * maxSide;
};
Given a 2D grid of integers, where each cell contains either a 0
or 1
, your goal is to find the area of the largest square whose borders are all 1
s. The square must be aligned with the grid (not rotated), and only the border cells of the square need to be 1
s—the interior may contain 0
s or 1
s. You should return the area (side length squared) of the largest such square. If no such square exists, return 0
.
grid
with m
rows and n
columns.
At first glance, you might think about checking every possible square in the grid to see if its border is all 1
s. This brute-force approach would involve iterating over all possible top-left and bottom-right corners, and then checking each side of the square, which can be very slow for large grids.
However, this approach is inefficient because you would end up checking the same rows and columns repeatedly. To optimize, you can precompute information about how many consecutive 1
s appear horizontally and vertically up to each cell. This way, you can quickly verify if a square's border is valid by just looking up values, instead of iterating through each border cell every time.
The key insight is to use dynamic programming to store these counts, reducing repeated work and making checks for valid borders fast.
1
s horizontally for each cell, and one for vertically.(i, j)
, if grid[i][j]
is 1
, update:
1
s to the left (including itself).1
s above (including itself).1
s using the precomputed matrices.This approach leverages dynamic programming for fast lookups and avoids redundant work, making it much more efficient than brute-force.
Consider the following grid as input:
grid = [ [1, 1, 1], [1, 0, 1], [1, 1, 1] ]
Let's walk through the steps:
1
s to the left and above.1
s.1
is found.
If the grid were missing a 1
on the border, the algorithm would automatically check smaller squares until it finds the largest valid one.
The optimized approach is efficient and suitable for large grids.
The problem of finding the largest 1-bordered square in a grid can be solved efficiently by precomputing the number of consecutive 1
s horizontally and vertically at each cell. This allows for quick verification of square borders, turning what could be a slow brute-force search into a fast dynamic programming solution. The elegance of this method lies in its use of extra space to save time, and its generalizability to similar "bordered" problems.