(LeetCode-Hot100)200. 岛屿数量

200. 岛屿数量

🔗 LeetCode 中文链接

复制代码
题解github地址: https://github.com/swf2020/LeetCode-Hot100-Solutions

📌 题目描述

给你一个由 '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

示例 2:

复制代码
输入:grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]
输出:3

💡 解题思路

本题本质上是求 连通分量的数量 ,其中每个连通分量由相邻的 '1' 构成。我们可以使用以下两种主流方法:

方法一:深度优先搜索(DFS)

  1. 遍历整个二维网格。
  2. 当遇到 '1' 时,说明发现了一个新岛屿,岛屿数量 +1。
  3. 使用 DFS 将该岛屿所有相连的 '1' 标记为 '0'(即"淹没"该岛),防止重复计数。
  4. 继续遍历直到结束。

优点 :代码简洁,逻辑清晰。

缺点:递归可能导致栈溢出(但在 LeetCode 数据规模下通常不会)。


方法二:广度优先搜索(BFS)

  1. 遍历网格。
  2. 遇到 '1' 时,岛屿数 +1,并启动 BFS。
  3. 使用队列将当前岛屿所有相连的 '1' 入队,并在访问后置为 '0'
  4. 直到队列为空,表示该岛屿已完全遍历。

优点 :避免递归,适合大规模数据。

缺点:需要额外队列空间。


方法三:并查集(Union-Find)

  1. 将每个 '1' 视为一个独立节点。
  2. 遍历网格,对每个 '1',检查其右方和下方是否也是 '1',若是,则合并。
  3. 最终统计并查集中连通分量的数量。

优点 :适合动态连通性问题。

缺点:实现较复杂,本题中不如 DFS/BFS 直观高效。

📌 推荐解法:DFS 或 BFS。本题采用 DFS 实现更简洁。


💻 代码实现

java 复制代码
class Solution {
    public int numIslands(char[][] grid) {
        if (grid == null || 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) {
        int m = grid.length, n = grid[0].length;
        // 边界检查或已访问(水)
        if (i < 0 || i >= m || j < 0 || j >= n || 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);
    }
}
go 复制代码
func numIslands(grid [][]byte) int {
    if len(grid) == 0 || len(grid[0]) == 0 {
        return 0
    }
    m, n := len(grid), len(grid[0])
    count := 0

    var dfs func(i, j int)
    dfs = func(i, j int) {
        if i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == '0' {
            return
        }
        grid[i][j] = '0'
        dfs(i+1, j)
        dfs(i-1, j)
        dfs(i, j+1)
        dfs(i, j-1)
    }

    for i := 0; i < m; i++ {
        for j := 0; j < n; j++ {
            if grid[i][j] == '1' {
                count++
                dfs(i, j)
            }
        }
    }
    return count
}

🔍 示例演示

以示例 2 为例:

复制代码
初始网格:
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1
  • 在 (0,0) 发现 '1' → 岛屿1,DFS 淹没左上角 2x2 区域。
  • 在 (2,2) 发现 '1' → 岛屿2,DFS 淹没单点。
  • 在 (3,3) 发现 '1' → 岛屿3,DFS 淹没右下角两个点。

最终返回 3


✅ 答案有效性证明

  • 正确性 :每次遇到未访问的 '1' 必定属于一个新岛屿(因为之前的 DFS/BFS 已清除所有已访问岛屿)。
  • 完整性:遍历所有格子,确保不遗漏任何岛屿。
  • 终止性:DFS/BFS 在有限网格中必然终止(每次递归/入队都缩小问题规模)。

因此,算法能正确统计所有连通的 '1' 区域数量。


📊 复杂度分析

方法 时间复杂度 空间复杂度 说明
DFS O ( M t i m e s N ) O(M \\times N) O(MtimesN) O ( M t i m e s N ) O(M \\times N) O(MtimesN) 最坏情况递归深度为 M t i m e s N M \\times N MtimesN(全为1)
BFS O ( M t i m e s N ) O(M \\times N) O(MtimesN) O ( m i n ( M , N ) ) O(\\min(M, N)) O(min(M,N)) 队列最大存储为对角线长度
并查集 O ( M t i m e s N c d o t a l p h a ( M N ) ) O(M \\times N \\cdot \\alpha(MN)) O(MtimesNcdotalpha(MN)) O ( M t i m e s N ) O(M \\times N) O(MtimesN) a l p h a \\alpha alpha 为阿克曼反函数,≈常数

其中 M M M 为行数, N N N 为列数。


🧠 问题总结

  • 常见错误 :忘记将访问过的 '1' 置为 '0',导致重复计数。
  • 关键思想连通分量计数 + 图遍历(DFS/BFS)
  • 💡 扩展思考
    • 若岛屿可斜向连接?→ 修改 DFS 方向为 8 个。
    • 若需返回最大岛屿面积?→ 在 DFS 中累加面积。
    • 动态添加陆地?→ 考虑并查集。

本题是 图论基础题,掌握后可轻松应对类似"区域染色"、"连通块统计"等问题。

相关推荐
A懿轩A2 小时前
【Java 基础编程】Java 常用类速查:包装类、String/StringBuilder、Math、日期类一篇搞定
java·开发语言·python·java常用类
田里的水稻2 小时前
LPC_激光点云定位(LSLAM)-正态分布变换(NDT)
人工智能·算法·数学建模·机器人·自动驾驶
宇木灵2 小时前
C语言基础-八、结构体和共同(用)体
c语言·开发语言·数据结构·笔记·学习·算法
plus4s2 小时前
2月21日(91-93题)
c++·算法
陈天伟教授2 小时前
人工智能应用- 材料微观:03. 微观结构:纳米金
人工智能·神经网络·算法·机器学习·推荐算法
盖头盖2 小时前
【Java反序列化之tabby半自动化挖掘新URLDNS链】
java
孞㐑¥2 小时前
算法—穷举,爆搜,深搜,回溯,剪枝
开发语言·c++·经验分享·笔记·算法
黄昏晓x2 小时前
C++----异常
android·java·c++
yaoxin5211232 小时前
330. Java Stream API - 处理 Optional 对象:像流一样优雅地使用 Optional
java·windows·python