并查集
并查集(Union-Find),也称为不相交集合数据结构(Disjoint-Set),主要用于处理一些 不相交集合的合并及查询。
核心操作
并查集提供两个核心操作:
- Find:确定某个元素属于哪一子集。即判断两个特定元素是否属于同一子集。
- Union:将两个子集归并成一个集合。
优化策略
1. 路径压缩 (Path Compression)
在执行 find 操作时,将节点的父指针指向其祖先,使得以后再查询该节点及其子节点时速度更快。目标是使树变得“扁平”。
2. 按秩合并 (Union by Rank/Size)
在执行 union 操作时,总是将高度(秩)较小的树根连接到高度较大的树根下,从而控制树的高度。
实现代码
public class UnionFind {
private int[] parent;
private int count; // 集合数量
public UnionFind(int n) {
parent = new int[n];
count = n;
for (int i = 0; i < n; i++) parent[i] = i;
}
// Find with Path Compression - O(α(n)) 接近 O(1)
public int find(int p) {
if (parent[p] != p) {
parent[p] = find(parent[p]); // 路径压缩
}
return parent[p];
}
// Union - O(α(n))
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) return;
parent[rootP] = rootQ; // 简单合并
count--;
}
public boolean connected(int p, int q) {
return find(p) == find(q);
}
public int count() {
return count;
}
}
典型应用
- 图的连通性:统计连通分量的数量。
- Kruskal 算法:检测边是否成环,构建最小生成树。
- 社交网络动态连接检测。
练习
- LeetCode 547:省份数量
- LeetCode 200:岛屿数量 (可以使用 BFS/DFS, 也可以用并查集)
- LeetCode 684:冗余连接
- LeetCode 990:等式方程的可满足性