Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目:给定一个由陆地和水组成的二维网格,其中陆地为1, 水为0。定义由水包围的陆地为岛屿,要求计算网格中岛屿的数量。假设网格的四条边均被水包围。
解题思路
在做本题之前,不妨看一下LeetCode 79.单词搜索这题,那题的要求是找到连续的字符在网格中,那么对于本题,我们是否可以把岛屿想象成较为复杂的连续字符,之后用单词搜索的思路即可。
单词搜索的思路是,我们首先要找到第一个符合要求的字符,然后对网格进行回溯即可,因为同一个网格的内容不能重复使用,因此我们可以使用一个标记数组来记录当前已经使用的字符,每次在查询的时候都查询即可,之后再对该字符上下左右字符进行回溯,最终如果要求的单词的字符全找到则可以返回true。
那么对于本题,我们可以先找到第一个符合要求的陆地,之后根据这个陆地进行上下左右回溯,在回溯过程中也设置标记数组标记已使用的陆地,每次回溯都查询即可,可得代码如下:
public int numIslands(char[][] grid) {
int numIsland = 0;
int[][] visited = new int[grid.length][grid[0].length];
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[0].length;j++){
if(grid[i][j]=='1' && visited[i][j]!=1){
search(grid, i, j, visited);
numIsland ++;
}
}
}
return numIsland;
}
public void search(char[][] grid, int i, int j, int[][] visited){
if(i<0 || j<0 || i>grid.length-1 || j>grid[0].length-1 || grid[i][j]=='0'|| visited[i][j] == 1) return ;
visited[i][j] = 1;
search(grid, i - 1, j, visited);
search(grid, i , j-1, visited);
search(grid, i + 1, j, visited);
search(grid, i, j + 1, visited);
}
上述代码的空间复杂度会较高,但本题并没有说不可以修改原数组,因此我们可以通过修改原数组来减少空间复杂度,修改的思路和标记数组不一样,标记数组只是查看当前陆地有没有被记录,而修改数组则是把陆地直接变成水,可得代码如下:
public int numIslands2(char[][] grid) {
int numIsland = 0;
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[0].length;j++){
if(grid[i][j]=='1'){
search2(grid, i, j);
numIsland ++;
}
}
}
return numIsland;
}
public void search2(char[][] grid, int i, int j){
if(i<0 || j<0 || i>grid.length-1 || j>grid[0].length-1 || grid[i][j]=='0') return ;
grid[i][j] = '0';
search2(grid, i - 1, j);
search2(grid, i , j-1);
search2(grid, i + 1, j);
search2(grid, i, j + 1);
}