voiddfs(int[][] grid, int i, int j, boolean[] visited){ int m = grid.length, n = grid[0].length; if (i < 0 || j < 0 || i >= m || j >= n) { // 超出索引邊界 return;
} if (visited[i][j]) { // 已遍歷過(guò) (i, j) return;
}
// 進(jìn)入節(jié)點(diǎn) (i, j)
visited[i][j] = true; // 遞歸遍歷上下左右的節(jié)點(diǎn) for (int[] d : dirs) { int next_i = i d[0]; int next_j = j d[1];
dfs(grid, next_i, next_j);
} // 離開(kāi)節(jié)點(diǎn) (i, j)
// visited[i][j] = true;
}
這種寫(xiě)法無(wú)非就是用 for 循環(huán)處理上下左右的遍歷罷了,你可以按照個(gè)人喜好選擇寫(xiě)法。
// 主函數(shù),計(jì)算島嶼數(shù)量 intnumIslands(char[][] grid){ int res = 0; int m = grid.length, n = grid[0].length; // 遍歷 grid for (int i = 0; i < m; i ) { for (int j = 0; j < n; j ) { if (grid[i][j] == '1') { // 每發(fā)現(xiàn)一個(gè)島嶼,島嶼數(shù)量加一
res ; // 然后使用 DFS 將島嶼淹了
dfs(grid, i, j);
}
}
} return res;
}
// 從 (i, j) 開(kāi)始,將與之相鄰的陸地都變成海水 voiddfs(char[][] grid, int i, int j){ int m = grid.length, n = grid[0].length; if (i < 0 || j < 0 || i >= m || j >= n) { // 超出索引邊界 return;
} if (grid[i][j] == '0') { // 已經(jīng)是海水了 return;
} // 將 (i, j) 變成海水
grid[i][j] = '0'; // 淹沒(méi)上下左右的陸地
dfs(grid, i 1, j);
dfs(grid, i, j 1);
dfs(grid, i - 1, j);
dfs(grid, i, j - 1);
}
為什么每次遇到島嶼,都要用 DFS 算法把島嶼「淹了」呢?主要是為了省事,避免維護(hù)visited數(shù)組。
// 主函數(shù):計(jì)算封閉島嶼的數(shù)量 intclosedIsland(int[][] grid){ int m = grid.length, n = grid[0].length; for (int j = 0; j < n; j ) { // 把靠上邊的島嶼淹掉
dfs(grid, 0, j); // 把靠下邊的島嶼淹掉
dfs(grid, m - 1, j);
} for (int i = 0; i < m; i ) { // 把靠左邊的島嶼淹掉
dfs(grid, i, 0); // 把靠右邊的島嶼淹掉
dfs(grid, i, n - 1);
} // 遍歷 grid,剩下的島嶼都是封閉島嶼 int res = 0; for (int i = 0; i < m; i ) { for (int j = 0; j < n; j ) { if (grid[i][j] == 0) {
res ;
dfs(grid, i, j);
}
}
} return res;
}
// 從 (i, j) 開(kāi)始,將與之相鄰的陸地都變成海水 voiddfs(int[][] grid, int i, int j){ int m = grid.length, n = grid[0].length; if (i < 0 || j < 0 || i >= m || j >= n) { return;
} if (grid[i][j] == 1) { // 已經(jīng)是海水了 return;
} // 將 (i, j) 變成海水
grid[i][j] = 1; // 淹沒(méi)上下左右的陸地
dfs(grid, i 1, j);
dfs(grid, i, j 1);
dfs(grid, i - 1, j);
dfs(grid, i, j - 1);
}
只要提前把靠邊的陸地都淹掉,然后算出來(lái)的就是封閉島嶼了。
intnumEnclaves(int[][] grid){ int m = grid.length, n = grid[0].length; // 淹掉靠邊的陸地 for (int i = 0; i < m; i ) {
dfs(grid, i, 0);
dfs(grid, i, n - 1);
} for (int j = 0; j < n; j ) {
dfs(grid, 0, j);
dfs(grid, m - 1, j);
}
// 數(shù)一數(shù)剩下的陸地 int res = 0; for (int i = 0; i < m; i ) { for (int j = 0; j < n; j ) { if (grid[i][j] == 1) {
res = 1;
}
}
}
return res;
}
// 和之前的實(shí)現(xiàn)類(lèi)似 voiddfs(int[][] grid, int i, int j){ // ...
}
篇幅所限,具體代碼我就不寫(xiě)了,我們繼續(xù)看其他的島嶼問(wèn)題。
intmaxAreaOfIsland(int[][] grid){ // 記錄島嶼的最大面積 int res = 0; int m = grid.length, n = grid[0].length; for (int i = 0; i < m; i ) { for (int j = 0; j < n; j ) { if (grid[i][j] == 1) { // 淹沒(méi)島嶼,并更新最大島嶼面積
res = Math.max(res, dfs(grid, i, j));
}
}
} return res;
}
// 淹沒(méi)與 (i, j) 相鄰的陸地,并返回淹沒(méi)的陸地面積 intdfs(int[][] grid, int i, int j){ int m = grid.length, n = grid[0].length; if (i < 0 || j < 0 || i >= m || j >= n) { // 超出索引邊界 return0;
} if (grid[i][j] == 0) { // 已經(jīng)是海水了 return0;
} // 將 (i, j) 變成海水
grid[i][j] = 0;
return dfs(grid, i 1, j)
dfs(grid, i, j 1)
dfs(grid, i - 1, j)
dfs(grid, i, j - 1) 1;
}
解法和之前相比差不多,我也不多說(shuō)了,接下來(lái)的兩道島嶼問(wèn)題是比較有技巧性的,我們重點(diǎn)來(lái)看一下。
intcountSubIslands(int[][] grid1, int[][] grid2){ int m = grid1.length, n = grid1[0].length; for (int i = 0; i < m; i ) { for (int j = 0; j < n; j ) { if (grid1[i][j] == 0