给定一个方阵,其中每个单元(像素)非黑即白。设计一个算法,找出 4 条边皆为黑色像素的最大子方阵。
返回一个数组 [r, c, size] ,其中 r, c 分别代表子方阵左上角的行号和列号,size 是子方阵的边长。若有多个满足条件的子方阵,返回 r 最小的,若 r 相同,返回 c 最小的子方阵。若无满足条件的子方阵,返回空数组。
示例 1:
输入:
[
[1,0,1],
[0,0,1],
[0,0,1]
]
输出: [1,0,2]
解释: 输入中 0 代表黑色,1 代表白色,标粗的元素即为满足条件的最大子方阵
示例 2:
输入:
[
[0,1,1],
[1,0,1],
[1,1,0]
]
输出: [0,0,1]
提示:
matrix.length == matrix[0].length <= 200```
注意:四边都为0就可以,一开始写的时候,用dfs
class Solution {
int[] res = new int[3];
public int[] findSquare(int[][] matrix) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == 0) {
dfs(i, j, 1, matrix);
}
}
}
if (res[2] == 0) return new int[0];
return res;
}
private void dfs(int r, int c, int s, int[][] matrix) {
if (s > res[2]) {
res[0] = r;
res[1] = c;
res[2] = s;
}
if (c + s >= matrix[0].length || r + s >= matrix.length) {
return;
}
// 1,0,1. -> 2
for (int i = r; i < r + s + 1 && i < matrix.length; i++) {
if(matrix[i][c + s] == 1) {
return;
}
}
for (int i = c; i < c + s + 1 && i < matrix[0].length; i++) {
if (matrix[r + s][i] == 1) {
return;
}
}
dfs(r, c, s + 1, matrix);
}
}
这样就算上内部的值了,只要求边长。
动态规划
class Solution {
public int[] findSquare(int[][] matrix) {
int[] res = new int[0];
int[][][] dp = new int[2][matrix.length + 1][matrix[0].length + 1];
int max = 0;
//2个状态 分别代表从右下角开始向上和向左的黑色块个数,0数组向上,1向左,注意只有格子为0的才会标记。重叠子问题
for (int i = 1; i <= matrix.length; i++) {
for (int j = 1; j <= matrix[0].length; j++) {
if (matrix[i - 1][j - 1] == 0) {
dp[0][i][j] = dp[0][i - 1][j] + 1;
dp[1][i][j] = dp[1][i][j - 1] + 1;
int bound = Math.min(dp[0][i][j], dp[1][i][j]);//得到最短边长
// 求当前另2边的最大长度,只需要算左和上两个顶点的最大长度,求最小。
while (bound > 0) {
if (bound > max && dp[1][i - bound + 1][j] >= bound && dp[0][i][j - bound + 1] >= bound) {
res = new int[3];
res[0] = i - bound;
res[1] = j - bound;
res[2] = bound;
max = bound;
}
bound--;
}
}
}
}
return res;
}
}