
并查集如同社交网络的关系管家:
union操作合并两个家族(家族联姻)
find操作追溯最终祖先(确认家族归属)
整个过程像动态维护社交圈:随时合并圈子,快速确认两人是否属于同一群体。
class UnionFind {
private int[] parent; // 父节点数组
private int[] rank; // 秩(树高)
public UnionFind(int size) {
parent = new int[size];
rank = new int[size];
for (int i = 0; i < size; i++) {
parent[i] = i; // 初始父节点是自己
rank[i] = 1; // 初始高度为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) {
if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
} else if (rank[rootX] < rank[rootY]) {
parent[rootX] = rootY;
} else {
parent[rootY] = rootX;
rank[rootX] += 1; // 树高增加
}
}
}
public boolean isConnected(int x, int y) {
return find(x) == find(y);
}
public static void main(String[] args) {
UnionFind uf = new UnionFind(5);
uf.union(0, 1);
uf.union(2, 3);
System.out.println(uf.isConnected(0, 1)); // true
System.out.println(uf.isConnected(1, 2)); // false
uf.union(1, 3);
System.out.println(uf.isConnected(0, 3)); // true
}
}指标 | 数值 | 说明 |
|---|---|---|
时间复杂度 | O(α(n)) ≈ O(1) | α为阿克曼函数的反函数,增长极慢 |
空间复杂度 | O(n) | 存储父节点和秩数组 |
特殊能力 | 动态连通性维护 | 支持实时合并和查询 |
优化精髓:
典型案例:
新手必练:
// LeetCode 547省份数量解法核心
public int findCircleNum(int[][] isConnected) {
int n = isConnected.length;
UnionFind uf = new UnionFind(n);
for(int i=0; i<n; i++){
for(int j=i+1; j<n; j++){
if(isConnected[i][j] == 1) uf.union(i,j);
}
}
return uf.getCount();
}高手进阶:
// 带权并查集示例(记录集合大小)
class WeightedUnionFind {
private int[] size; // 新增大小数组
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (size[rootX] < size[rootY]) {
parent[rootX] = rootY;
size[rootY] += size[rootX];
} else {
parent[rootY] = rootX;
size[rootX] += size[rootY];
}
}
}
}并查集教会我们:
当你能在百万级用户的社交网络中实时判断任意两人的联系路径时,说明真正掌握了动态连通性的精髓——这不仅需要算法理解,更需要将简单结构发挥到极致的工程智慧。记住:优秀的数据结构如同社会关系,既要保持连接的高效,又要允许动态的演化。