并查集实现
- parent:记录每个节点的父节点
- size:记录每棵树的重量,目的是 union 后树依然保持平衡性
- 路径压缩:保证任意数的高度为常数
public class UF {
// 连通分量个数
private int count;
// 存储一个树
private int[] parent;
// 记录树的重量(将小一些的树接到大一些的树下面)
private int[] size;
public UF(int n) {
this.count = n;
// 最初每棵树只有一个节点
// 重量初始化为 1
parent = new int[n];
size = new int[n];
for(int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
}
// 寻找父节点
private int find(int x) {
while(parent[x] != x) {
// 路径压缩(父节点改为根节点)
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
// 合并
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if(rootP == rootQ) {
return;
}
// 小树接到大树下面
if(size[rootP] > size[rootQ]) {
parent[rootQ] = rootP;
size[rootP] += size[rootQ];
}else {
parent[rootP] = rootQ;
size[rootQ] += size[rootP];
}
count--;
}
// 二者是否连通
public boolean connected(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
return rootP == rootQ;
}
public int count() {
return count;
}
}
应用
- 等式方程的可满足性(leedcode-990)
public boolean equationsPossible(String[] equations) {
UF uf = new UF(26);
for(String s : equations) {
if(s.charAt(1) == '=') {
uf.union(s.charAt(0) - 'a', s.charAt(3) - 'a');
}
}
for(String s : equations) {
if(s.charAt(1) == '!') {
if(uf.connected(s.charAt(0) - 'a', s.charAt(3) - 'a')) {
return false;
}
}
}
return true;
}