当然可以!用 并查集(Union-Find) 解决 LeetCode 第 200 题 “岛屿数量”(Number of Islands) 是一个非常经典的应用。虽然这题更常见的解法是 DFS/BFS,但用并查集不仅能做,还能加深你对 DSU 的理解!

🌊 问题简述
给定一个由 '1'(陆地)和 '0'(水)组成的二维网格 grid,计算岛屿的数量。  
岛屿是由上下左右相邻的 '1' 连成的一整块区域。

💡 并查集思路
1. 每个格子是一个节点:总共有 m * n 个节点。
2. 初始时,所有 '1' 都是独立的岛屿(即各自为根)。
3. 遍历网格:对每个 '1',检查它的右邻居和下邻居(避免重复):
   - 如果邻居也是 '1',就把它们所在的集合合并(union)。
4. 最终岛屿数 = 所有 '1' 的数量 - 合并次数,或者更简单:统计并查集中根节点的数量(仅限 '1' 的位置)。

✅ 为什么只看右和下?因为左和上已经在之前的遍历中处理过了,避免重复 union。

✅ 完整 Java 代码(带详细注释)

public class Solution {
    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0 || grid.length == 0) {
            return 0;
        }
        
        int m = grid.length;
        int n = grid.length;
        UnionFind uf = new UnionFind(m * n);
        int landCount = 0; // 统计陆地总数
        
        // 先统计有多少个 '1'
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '1') {
                    landCount++;
                }
            }
        }
        
        // 遍历每个格子,向右、向下合并
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '1') {
                    // 当前位置在一维数组中的索引
                    int idx = i * n + j;
                    
                    // 检查右边
                    if (j + 1 < n && grid[i][j + 1] == '1') {
                        uf.union(idx, i * n + (j + 1));
                    }
                    
                    // 检查下边
                    if (i + 1 < m && grid[i + 1][j] == '1') {
                        uf.union(idx, (i + 1) * n + j);
                    }
                }
            }
        }
        
        // 岛屿数量 = 陆地数量 - 合并次数
        // 但更直接的方式:统计所有 '1' 中,根节点的数量
        int islandCount = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '1') {
                    int idx = i * n + j;
                    if (uf.find(idx) == idx) { // 自己是根 → 一个岛屿
                        islandCount++;
                    }
                }
            }
        }
        
        return islandCount;
    }

    // 内部类:并查集(带路径压缩 + 按大小合并)
    static class UnionFind {
        private int[] parent;
        private int[] size;

        public UnionFind(int n) {
            parent = new int[n];
            size = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                size[i] = 1;
            }
        }

        public int find(int x) {
            if (parent[x] != x) {
                parent[x] = find(parent[x]); // 路径压缩
            }
            return parent[x];
        }

        public void union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            if (rootX == rootY) return;

            // 按大小合并
            if (size[rootX] < size[rootY]) {
                parent[rootX] = rootY;
                size[rootY] += size[rootX];
            } else {
                parent[rootY] = rootX;
                size[rootX] += size[rootY];
            }
        }
    }
}

🔍 关键点解析
- 一维映射:二维坐标 (i, j) → 一维索引 i * n + j,这是并查集处理网格的标准技巧。
- 只向右/下合并:避免重复操作(比如 (0,0) 和 (0,1) 合并后,(0,1) 就不需要再和 (0,0) 合并了)。
- 统计根节点:只有 '1' 的位置才可能是岛屿的一部分,所以只在这些位置检查 find(idx) == idx。

⏱️ 复杂度
- 时间复杂度:接近 O(m × n)(因为并查集操作均摊 O(1))
- 空间复杂度:O(m × n)(并查集数组)

🧪 测试一下?
输入:
char[][] grid = {
    {'1','1','0','0','0'},
    {'1','1','0','0','0'},
    {'0','0','1','0','0'},
    {'0','0','0','1','1'}
};

输出:3 ✅

需要我帮你改成 按秩合并 版本?或者想看看 DFS/BFS 对比?随时告诉我! 😄

 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐