51.岛屿数量
200. 岛屿数量
给你一个由
'1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [ ['1','1','1','1','0'], ['1','1','0','1','0'], ['1','1','0','0','0'], ['0','0','0','0','0'] ] 输出:1
方法dfs————来源:nettee
二叉树的 DFS 有两个要素:「访问相邻结点」和「判断 base case」。
第一个要素是访问相邻结点。二叉树的相邻结点非常简单,只有左子结点和右子结点两个。二叉树本身就是一个递归定义的结构:一棵二叉树,它的左子树和右子树也是一棵二叉树。那么我们的 DFS 遍历只需要递归调用左子树和右子树即可。
第二个要素是 判断 base case。一般来说,二叉树遍历的 base case 是 root == null。这样一个条件判断其实有两个含义:一方面,这表示 root 指向的子树为空,不需要再往下遍历了。另一方面,在 root == null 的时候及时返回,可以让后面的 root.left 和 root.right 操作不会出现空指针异常。
同理——图的相邻结点 : 上下左右;图的判断base case:超没超范围
如何避免重复遍历
答案是标记已经遍历过的格子。以岛屿问题为例,我们需要在所有值为 1 的陆地格子上做 DFS 遍历。每走过一个陆地格子,就把格子的值改为 2,这样当我们遇到 2 的时候,就知道这是遍历过的格子了。也就是说,每个格子可能取三个值:
0 —— 海洋格子
1 —— 陆地格子(未遍历过)
2 —— 陆地格子(已遍历过)
class Solution { // 岛屿数量计数器 int count = 0; public int numIslands(char[][] grid) { // 处理空网格的边界情况,避免空指针 if (grid == null || grid.length == 0) { return 0; } int rows = grid.length; int cols = grid[0].length; // 遍历网格中的每一个位置 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { // 发现未访问的陆地('1'),说明找到一个新岛屿 if (grid[i][j] == '1') { count++; // 岛屿数量加1 // 用DFS标记该岛屿的所有相邻陆地为已访问('2') dfs(grid, i, j); } } } return count; } // 深度优先搜索:标记当前岛屿的所有相邻陆地为已访问 public void dfs(char[][] grid, int r, int c) { // 检查当前坐标是否在网格范围内 if (!inArea(grid, r, c)) return; // 如果当前位置不是未访问的陆地(是水或已访问的陆地),直接返回 if (grid[r][c] != '1') { return; } // 标记为已访问(用'2'代替,避免重复计数) grid[r][c] = '2'; // 向四个相邻方向递归遍历(上、下、左、右) dfs(grid, r - 1, c); // 上 dfs(grid, r + 1, c); // 下 dfs(grid, r, c - 1); // 左 dfs(grid, r, c + 1); // 右 } // 判断坐标(r,c)是否在网格的有效范围内 public boolean inArea(char[][] grid, int r, int c) { return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length; } }
【背!!n老师太牛了,讲的明明白白】

浙公网安备 33010602011771号