【LeetCode-动态规划】最大的以 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
题目链接: https://leetcode-cn.com/problems/largest-1-bordered-square/
思路
这题和统计全 1 子矩形有点类似,使用动态规划来做。
- 状态定义:使用两个状态:left[i][j] 表示位置 (i, j) 左边 1 的个数(包括位置 (i, j)),up[i][j] 表示位置 (i, j) 上边 1 的个数(包括位置 (i, j));
- 状态转移:如果 grid[i][j]==1,left[i][j] = left[i][j-1] + 1,up[i][j] = up[i-1][j] + 1;
- 边界条件(grid[i][j]==1 的情况下):
- i==0 && j==0:left[i][j] = up[i][j] = 1;
- i==0 && j!=0:left[i][j] = left[i][j-1] + 1; up[i][j] = 1;
- i!=0 && j==0:left[i][j] = 1; up[i][j] = up[i-1][j] + 1;
对于每一个位置(i, j),left[i][j] 表示该位置左边有多少 1,up[i][j] 表示该位置上边有多少 1,则以位置 (i, j) 为右下角的正方形的最大边长 len = min(left[i][j], up[i][j]),我们需要判断 left[i-k+1][j](右上角) 和 up[i][j-k+1](左下角)1 的个数是不是大于等于 k,k ∈ [1, len],选择最大的 k 作为以位置 (i, j) 为右下角的正方形的边长。在遍历的过程中记录最大边长。代码如下:
class Solution {
public:
int largest1BorderedSquare(vector<vector<int>>& grid) {
if(grid.empty()) return 0;
int m = grid.size();
int n = grid[0].size();
vector<vector<int>> left(m, vector<int>(n, 0));
vector<vector<int>> up(m, vector<int>(n, 0));
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(grid[i][j]==1){
if(i==0 && j==0){
left[i][j] = 1;
up[i][j] = 1;
}else if(i==0){
left[i][j] = left[i][j-1] + 1;
up[i][j] = 1;
}else if(j==0){
left[i][j] = 1;
up[i][j] = up[i-1][j] + 1;
}else{
left[i][j] = left[i][j-1] + 1;
up[i][j] = up[i-1][j] + 1;
}
}
}
}
int ans = 0;
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
int len = min(left[i][j], up[i][j]);
for(int k=len; k>0; k--){
if(left[i-k+1][j]>=k && up[i][j-k+1]>=k){
ans = max(ans, k);
break;
}
}
}
}
return ans*ans;
}
};
- 时间复杂度:O(mn)
- 空间复杂度:O(mn)