并查集
并查集,简单来说,是一种用来解决集合查询和合并的数据结构。支持支持O(1)查询(find),和O(1)合并(union)。
1. 并查集可以干什么
- 判断两个值是否在同一集合(find 操作)
- 将两个集合合并(union 操作)
2. 并查集的时间复杂度
上面说find和union是O(1)的,但准确来说是logn,注意这个和logn是不一样的,这logn大家可以查一下,它在n很大很大的时候,它仍然很小很小。所以我们才说是O(1)。
3. 查询find和合并union的模板(C++)
int find(int x) {
if (x == father[x]) {
return x;
}
return father[x] = find(father[x]);//压缩路径的写法
}
void Union(int a, int b) {
int root_a = find(a);
int root_b = find(b);
if (root_a != root_b) {
father[root_a] = root_b;
}
}
这里有一个路径压缩的概念,是这样的:比如1->2->3->4->5…->n("->"代表两点相连),此时要找n时,那先找1,在通过1找到2,以此类推找到n,如果每次find时,都进行这样的操作的话,这时find的操作就会是O(n)的。而路径压缩指的是,你第一次find时,寻找n的过程中,改变连接关系,使得第一次寻找完之后,连接关系变为1->n,2->n,3->n,4->n,5->n,以此类推,也就是说,所有点在第一次操作之后都连向同一个“父亲”节点。上面father[x] = find(father[x]);
语句,就可以实现这个。
如果不进行路径压缩的话,那朴素的find方法如下:
int find(int x) {
if (x == father[x]) {
return x;
}
return find(father[x]);//朴素方法 O(n)的
}
4. 并查集的操作
4.1 并查集原生操作:
- 查询两个元素是否在同一个集合内
- 合并两个元素所在的集合
例题:https://www.jiuzhang.com/solutions/connecting-graph/
4.2 并查集的派生操作:
- 查询某个元素所在集合的元素个数
例题:http://www.jiuzhang.com/solutions/connecting-graph-ii/ - 查询当前集合的个数
例题:
(1)http://www.jiuzhang.com/solutions/connecting-graph-iii/
(2)【并查集】Leetcode 547.省份数量