200. 岛屿数量(Number of Islands)

频次 ★★★★★ · 难度 🟡 · 高频:全厂

题目

m×n 网格,‘1’ 是陆地、‘0’ 是水,四联通,求岛屿数量。

示例

输入:
11110
11010
11000
00000
输出: 1

思路

DFS 沉没法:遍历网格,每遇到一个 ‘1’ 就计数 +1,然后递归把和它四联通的 ‘1’ 全改成 ‘0’(“沉没”该岛)。

BFS 或并查集也行,但 DFS 最简洁。

代码

public int numIslands(char[][] grid) {
    if (grid.length == 0) return 0;
    int m = grid.length, n = grid[0].length;
    int count = 0;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (grid[i][j] == '1') {
                count++;
                dfs(grid, i, j);
            }
        }
    }
    return count;
}
 
private void dfs(char[][] grid, int i, int j) {
    if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == '0')
        return;
    grid[i][j] = '0';                     // 沉没
    dfs(grid, i + 1, j);
    dfs(grid, i - 1, j);
    dfs(grid, i, j + 1);
    dfs(grid, i, j - 1);
}

复杂度

  • 时间:O(m×n) —— 每个格子至多访问一次
  • 空间:O(m×n) 最坏 —— 全 ‘1’ 时递归栈深度 m×n

边界条件

  • 空网格:返回 0
  • 全 0 / 全 1:返回 0 / 1
  • 单行/单列:正常 DFS
  • 网格很大(1000×1000):递归可能栈溢出,改 BFS 或显式栈

变式

易错点

  • 输入是 char[][] 不是 int[][]:比较时用 '1''0' 别写数字
  • DFS 沉没后不需要恢复(修改原数组),和回溯的”恢复现场”不同——因为”访问过”就是永久标记
  • 四联通(上下左右)不要写成八联通(加对角线)

面试追问

  • BFS 怎么写? 用队列存坐标,每遇到 ‘1’ 就 BFS 四方向扩散并标记。递达复杂度相同,适合大网格防栈溢出
  • 并查集怎么做? 每个 ‘1’ 格子看做一个节点,与四联通方向的 ‘1’ union,最后统计根的个数。虽然代码长,但展示了对并查集的理解

关联题

  • 同套路:994. 腐烂的橘子 —— 多源 BFS 版”感染”问题
  • 进阶:207. 课程表 —— 图的遍历从网格换到邻接表
  • 知识点:网格图的 DFS 遍历模板见