千问 java 用并查集解决“岛屿数量”问题的完整代码
当然可以!用 并查集(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 对比?随时告诉我! 😄
更多推荐




所有评论(0)