并查集:连通性、按秩合并与路径压缩
动态维护「是否同属一类」:朋友圈、电路连通、Kruskal——并查集几乎是标配。
并查集(Disjoint Set Union)支持两类操作:Find(查根)与 Union(合并集合)。配合按秩合并与路径压缩,均摊复杂度近乎常数。
实现骨架
type DSU struct {
parent, rank []int
}
func NewDSU(n int) *DSU {
p := make([]int, n)
for i := range p {
p[i] = i
}
return &DSU{parent: p, rank: make([]int, n)}
}
func (d *DSU) Find(x int) int {
if d.parent[x] != x {
d.parent[x] = d.Find(d.parent[x]) // 路径压缩
}
return d.parent[x]
}
func (d *DSU) Union(a, b int) bool {
ra, rb := d.Find(a), d.Find(b)
if ra == rb {
return false
}
if d.rank[ra] < d.rank[rb] {
ra, rb = rb, ra
}
d.parent[rb] = ra
if d.rank[ra] == d.rank[rb] {
d.rank[ra]++
}
return true
}
应用速览
- 判断无向图连通分量 / 环(加边前已同根则成环)。
- Kruskal 最小生成树的边筛选。
- 等价关系的传递闭包式查询(账户合并、岛屿数量变体等)。
小结
结构简单,威力在「动态」。下次遇到不断加关系、反复问是否连通,优先想到并查集,而不是每次 DFS。