介绍
并查集又称Union-Find,属于图的一种,是一种很不一样的树结构
应用
- 处理连接问题,比如网络(抽象的概念,不特指因特网)间节点的连接状态;
- 数学中的集合类实现,比如求两个集合中的并集;
实现
详细分析请看这篇文章:labuladong.gitee.io/algo/2/19/3…
class UF {
count = 0;
size = [];
parent = [];
// n 为图中节点的个数
constructor(n) {
this.count = n;
this.parent = [];
this.size = [];
for (let i = 0; i < n; i++) {
this.parent[i] = i;
this.size[i] = 1;
}
}
// 将节点 x 和节点 y 连通
union(x, y) {
const xr = this.find(x);
const yr = this.find(y);
if (xr === yr) return;
// 小树接到大树下面,使树整体平衡
if (this.size[xr] < this.size[yr]) {
this.parent[xr] = yr;
this.size[yr] += this.size[xr];
} else {
this.parent[yr] = xr;
this.size[xr] += this.size[yr];
}
this.count--;
}
// 判断节点 x 和节点 y 是否连通
isConnected = (x, y) => this.find(x) === this.find(y);
// 返回节点 x 的根节点
find(x) {
while (x !== this.parent[x]) {
this.parent[x] = this.parent[this.parent[x]];
x = this.parent[x];
}
return x;
}
// 返回图中的连通分量个数
count() {
return this.count;
}
}
解析
如下图所示,共有10个节点,连通分量为 10 个;
第一次,调用union(0,1),连通0和1,连通分量降为 9 个;
第二次,调用union(1,2),连通1和2,连通分量变为 8 个;
这时调用 isConnected(0,2)返回true
连通的性质:
1、自反性:节点 x 和 y 是连通的;
2、对称性:如果节点 x 和 y 连通,那么 y 和 x 也连通;
3、传递性:如果节点 x 和 y 连通,y 和 z 连通,那么 x 和 z 也连通。
力扣刷题
题目:990. 等式方程的可满足性
解答
先构建连通性,然后再处理!=是否破坏了连通性;
function equationsPossible(equations) {
const uf = new UF(26);
const codeA = "a".charCodeAt(0);
// 构建连通性
for (let i = 0; i < equations.length; i++) {
const item = equations[i];
if (item[1] === "=") {
uf.union(item[0].charCodeAt(0) - codeA, item[3].charCodeAt(0) - codeA);
}
}
// 处理!=是否破坏了连通性
for (let i = 0; i < equations.length; i++) {
const item = equations[i];
if (item[1] === "!") {
if (
uf.isConnected(
item[0].charCodeAt(0) - codeA,
item[3].charCodeAt(0) - codeA
)
) {
return false;
}
}
}
return true;
}
class UF {
count = 0;
size = [];
parent = [];
constructor(n) {
this.count = n;
this.parent = [];
this.size = [];
for (let i = 0; i < n; i++) {
this.parent[i] = i;
this.size[i] = 1;
}
}
union(x, y) {
const xr = this.find(x);
const yr = this.find(y);
if (xr === yr) return;
// 小树接到大树下面,较平衡
if (this.size[xr] < this.size[yr]) {
this.parent[xr] = yr;
this.size[yr] += this.size[xr];
} else {
this.parent[yr] = xr;
this.size[xr] += this.size[yr];
}
this.count--;
}
isConnected = (x, y) => this.find(x) === this.find(y);
find(x) {
while (x !== this.parent[x]) {
this.parent[x] = this.parent[this.parent[x]];
x = this.parent[x];
}
return x;
}
count() {
return this.count;
}
}