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”的個數),這個臂長中的最小值即爲以該單元格爲中心的軸對稱加號的階。
這種方法的時間複雜度爲,空間複雜度爲.
思路2:動態規劃 - 優化的暴力法。其實,對於值爲每個單1的單元格,其向左、向右、向上、向下四個方向的連續“1”的個數是可以提前計算出來的。
比如,對於某一行,每個位置向左方向連續“1”的個數爲。
具體的計算方法如下:
/*注意:
下列算法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};
時間複雜度:.
空間複雜度:.
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;
}
};