Description
In a 2D grid
from (0, 0) to (N-1, N-1), every cell contains a 1
, except those cells in the given list mines
which are 0
. What is the largest axis-aligned plus sign of 1
s contained in the grid? Return the order of the plus sign. If there is none, return 0.
An "axis-aligned plus sign of 1
s of order k" has some center grid[x][y] = 1
along with 4 arms of length k-1
going up, down, left, and right, and made of 1
s. This is demonstrated in the diagrams below. Note that there could be 0
s or 1
s beyond the arms of the plus sign, only the relevant area of the plus sign is checked for 1s.
Examples of Axis-Aligned Plus Signs of Order k:
Order 1:
000
010
000
Order 2:
00000
00100
01110
00100
00000
Order 3:
0000000
0001000
0001000
0111110
0001000
0001000
0000000
Example 1:
Input: N = 5, mines = [[4, 2]]
Output: 2
Explanation:
11111
11111
11111
11111
11011
In the above grid, the largest plus sign can only be order 2. One of them is marked in bold.
Example 2:
Input: N = 2, mines = []
Output: 1
Explanation:
There is no plus sign of order 2, but there is of order 1.
Example 3:
Input: N = 1, mines = [[0, 0]]
Output: 0
Explanation:
There is no plus sign, so return 0.
Note:
-
N
will be an integer in the range[1, 500]
. -
mines
will have length at most5000
. -
mines[i]
will be length 2 and consist of integers in the range[0, N-1]
. - (Additionally, programs submitted in C, C++, or C# will be judged with a slightly smaller time limit.)
Solution
题目好长,翻译过来就是在一个01稀疏矩阵中找由连续1组成的最大的十字架(十字架每条边长度相等)。
3D-DP + HashSet, time O(n ^ 2), space O(n ^ 2)
三维DP,int[][][] dp = new int[n + 2][n + 2][4],z维度表示四个方向。
注意对于坐标(i, j)来说,它依赖于上下左右四个方向的dp值,所以还需要从后往前遍历。
由于mines是一组坐标,可以将其转换成一维存在HashSet中,方便查询。
class Solution {
// up, left, down, right
public static final int[][] DIRECTIONS = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
public int orderOfLargestPlusSign(int n, int[][] mines) {
int[][][] dp = new int[n + 2][n + 2][4];
Set<Integer> mineSet = new HashSet<>();
for (int[] mine : mines) {
mineSet.add(getIndex(mine[0], mine[1], n));
}
// traverse from up to bottom, left to right
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (mineSet.contains(getIndex(i, j, n))) {
continue;
}
for (int k = 0; k < 2; ++k) {
dp[i + 1][j + 1][k]
= 1 + dp[i + 1 + DIRECTIONS[k][0]][j + 1 + DIRECTIONS[k][1]][k];
}
}
}
// traverse from bottom to up, right to left
int max = 0;
for (int i = n - 1; i >= 0; --i) {
for (int j = n - 1; j >= 0; --j) {
if (mineSet.contains(getIndex(i, j, n))) {
continue;
}
for (int k = 2; k < 4; ++k) {
dp[i + 1][j + 1][k]
= 1 + dp[i + 1 + DIRECTIONS[k][0]][j + 1 + DIRECTIONS[k][1]][k];
}
// update max when 4 directions are done
max = Math.max(min(dp[i + 1][j + 1]), max);
}
}
return max;
}
public int getIndex(int i, int j, int n) {
return i * n + j;
}
public int min(int[] a) {
int min = Integer.MAX_VALUE;
for (int n : a) {
min = Math.min(n, min);
}
return min;
}
}
2D-DP + HashSet, time O(n ^ 2), space O(n ^ 2)
下面这种写法更清晰一点,推荐。
class Solution {
public int orderOfLargestPlusSign(int n, int[][] mines) {
int[][] dp = new int[n][n];
Set<Integer> mineSet = new HashSet<>();
for (int[] mine : mines) {
mineSet.add(getIndex(mine[0], mine[1], n));
}
for (int i = 0; i < n; ++i) {
int count = 0;
for (int j = 0; j < n; ++j) {
count = mineSet.contains(getIndex(i, j, n)) ? 0 : count + 1;
dp[i][j] = count;
}
count = 0;
for (int j = n - 1; j >= 0; --j) {
count = mineSet.contains(getIndex(i, j, n)) ? 0 : count + 1;
dp[i][j] = Math.min(count, dp[i][j]);
}
}
int max = 0;
for (int j = 0; j < n; ++j) {
int count = 0;
for (int i = 0; i < n; ++i) {
count = mineSet.contains(getIndex(i, j, n)) ? 0 : count + 1;
dp[i][j] = Math.min(count, dp[i][j]);
}
count = 0;
for (int i = n - 1; i >= 0; --i) {
count = mineSet.contains(getIndex(i, j, n)) ? 0 : count + 1;
dp[i][j] = Math.min(count, dp[i][j]);
max = Math.max(dp[i][j], max);
}
}
return max;
}
public int getIndex(int i, int j, int n) {
return i * n + j;
}
}