1、问题描述
在一个大小在(0,0)到(N-1,N-1)的2D网格grid中,除了mines给出的单元格为0,其他单元格都为1。网格中包含1的最大轴对称加号的阶是多少,返回最大轴对称加号的阶。如果不存在轴对称加号,则返回0.
一个k阶轴由1组成的轴对称加号指的是具有中心网格grid[x][y],以及从中心向上、向下、向左、向右延伸,长度为k-1,由1组成的臂,下面给出 k" 阶“轴对称”加号标志的示例。
阶 1:
000
010
000阶 2:
00000
00100
01110
00100
00000阶 3:
0000000
0001000
0001000
0111110
0001000
0001000
0000000
示例1:
输入: N = 5, mines = [[4, 2]]
输出: 2
解释:11111
11111
11111
11111
11011
在上面的网格中,最大加号标志的阶只能是2。一个标志已在图中标出。
示例2:
输入: N = 2, mines = []
输出: 1
解释:11
11
没有 2 阶加号标志,有 1 阶加号标志。
2、解题思路
思路1:暴力法。我们可以每个为“1”的单元格为中心,计算其向上、向下、向左、向右四个方向的臂长(即该单元格向这个四个方向的连续“1”的个数),这个臂长中的最小值即为以该单元格为中心的轴对称加号的阶。
这种方法的时间复杂度为
O
(
N
3
)
O(N^3)
O(N3),空间复杂度为
O
(
1
)
O(1)
O(1).
思路2:动态规划 - 优化的暴力法。其实,对于值为每个单1的单元格,其向左、向右、向上、向下四个方向的连续“1”的个数是可以提前计算出来的。
比如,对于某一行
[
1
,
0
,
1
,
1
,
1
,
0
,
1
,
1
]
[1,0,1,1,1,0,1,1]
[1,0,1,1,1,0,1,1],每个位置向左方向连续“1”的个数为
[
1
,
0
,
1
,
2
,
3
,
0
,
1
,
2
]
[1,0,1,2,3,0,1,2]
[1,0,1,2,3,0,1,2]。
具体的计算方法如下:
/*注意:
下列算法row[j]表示某一行的第j列元素;
dp[j]表示从左边界开始到row[j]连续1的个数。
*/
#for j = 0 to len:
*if(row[j] == 0):
#dp[j] = 0;
*else if(row[j] == 1):
#if(j > 0 && row[j-1] == 1):
*dp[j] = dp[j-1]+1;
#else:
*dp[j] = 1;
只要使用类似上述的方法求出每个为“1"的单元格向上、向下、向左、向右四个方向的连续1的个数,并存储在up、down、left、right中,则以该单元格为中心的轴对称加号的阶为min{left,right,up,down};
时间复杂度:
O
(
N
2
)
O(N^2)
O(N2).
空间复杂度:
O
(
N
2
)
O(N^2)
O(N2).
3、代码实现
/*基本思想:
对于每个网格grid[r][c],分别计算从gird[r][c]开始, left、right、up、down四个方向上1的连续个数,
并把它们存储下来,则以grid[r][c]为中心的轴对称加号标志的最大阶
dp[r][c] = min{left[r][c],right[r][c],up[r][c],down[r][c]}
计算left[r][c]的规则如下:
(1) 如果grid[r][c] 等于0,则left[r][c]为0;
(2) 如果grid[r][c]等于1并且它的前一个也为1,则left[r][c] = left[r][c-1] + 1, 否则left[r][c] = 1;
假设gird有一行为0111011,则left为0123012*/
class Solution {
public:
int orderOfLargestPlusSign(int N, vector<vector<int>>& mines) {
vector<vector<int>> grid(N,vector<int>(N,1));
for(int i = 0; i < mines.size(); i++){
grid[mines[i][0]][mines[i][1]] = 0;
}
vector<vector<int>> left(N,vector<int>(N,0));
vector<vector<int>> right(N, vector<int>(N,0));
vector<vector<int>> up(N,vector<int>(N,0));
vector<vector<int>> down(N, vector<int>(N,0));
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
if(grid[i][j] == 0){
left[i][j] = 0;
}
else{
if(j > 0 && grid[i][j-1] == 1){
left[i][j] = left[i][j-1] + 1;
}
else{
left[i][j] = 1;
}
}
int k = N-1-j;
if(grid[i][k] == 0){
right[i][k] = 0;
}
else{
if(k < N-1 && grid[i][k+1] == 1){
right[i][k] = right[i][k+1] + 1;
}
else{
right[i][k] = 1;
}
}
if(grid[j][i] == 0){
up[j][i] = 0;
}
else{
if(j > 0 && grid[j-1][i] == 1){
up[j][i] = up[j-1][i] + 1;
}
else{
up[j][i] = 1;
}
}
int p = N-1-j;
if(grid[p][i] == 0){
down[p][i] = 0;
}
else{
if(p < N-1 && grid[p+1][i] == 1){
down[p][i] = down[p+1][i] + 1;
}
else{
down[p][i] = 1;
}
}
}
}
int maxlen = 0;
for(int r = 0; r < N; r++){
for(int c = 0; c < N; c++){
// cout<<"r="<<r<<"c="<<c<<":"<<"("<<left[r][c]<<","<<right[r][c]<<","<<up[r][c]<<","<<down[r][c]<<")"<<endl;
int len = min(min(left[r][c],right[r][c]),min(up[r][c],down[r][c]));
if(len > maxlen){
maxlen = len;
}
}
}
return maxlen;
}
};