今天我们来讲讲并查集
什么是并查集?事实上并查集并不难,pipi用一个生动的例子带你了解并查集。
视频链接戳:
https://www.bilibili.com/video/BV14E411F7bb?from=search&seid=17815044715014992913
在这个视频例子中, 我们主要需要解决几个问题:
1.如何判断两个小弟(小a和小c)是否在同一个帮
2.如何合并两个帮派
我们来解析例子:
我们通过例子从以下四点来了解并查集:
1.并查集的初始状态
小a在没有跟随小b的时候,小a和小b是各自为营的,即小a和小b各自为自己的老大。
并查集的初始状态,也是各自为营,即集合的各个元素的leader是自己,我们记成:
leaderdict= { a的老大:a, b的老大:b, }
小a想要加入小b的帮派,怎么做呢?将a的老大改成b,b的老大保持不变,记成:
leaderdict= { a的老大:b, b的老大:b, }
2.判断两个集合是否为同一集合
在未合并前,如何判断小a和小c是否在同一个帮?
此时leaderdict中的记录状态是这样的
leaderdict= { a的老大:b, b的老大:b, c的老大:d, d的老大:f, f的老大:f, }
我们通过找寻小a和小c所在帮的帮主是否为同一个来判断两个帮是否为同个帮。
如何找寻帮主呢?当一个人的老大是自己的时候,那么这个人便是这个帮的帮主。
a的老大是b,b的老大是自己,b的老大是自己,那么b为小b帮帮主;
c的老大是c,c的老大是d,d的老大是f,f的老大是自己,那么f为小f帮帮主。
即判断两个集合是否为同个集合,需要先寻找两个集合各自的最终的老大,即集合的代表结点;
找老大的伪代码如下:
def FindLeader(元素c): 如果元素c的老大等于元素c: 返回元素c的老大 否则: FindLeader(元素c的老大)
然后判断两个集合的老大是否相同,如果不相同,说明不在同个集合,否则说明在同个集合。
判断两个集合是否为同一集合伪代码如下:
def IsSameSet(元素a,元素c): a的老大 = FindLeader(元素a) b的老大 = FindLeader(元素b) 返回 (a的老大 == b的老大)的结果
3.找老大的优化方案
我们通过判断两个集合的代表结点是否为同一个结点来判断两个集合是否为同一个集合,在这个寻找代表结点的过程中,其实我们可以进行一个优化:
比如我们找到了c的帮主是f,我们完全就可以将c的老大的值设置为f,同理d的老大的值可以设置成f
即
{ c的老大:f, d的老大:f, }
优化前
优化后
这样做的好处是明显的,如果下一次需要查找c和其他结点是否在同一个集合(同一个帮),我们只需要找1次集合的代表结点,大大节省时间。
优化后找老大的伪代码:
def FindLeader(元素): while(如果该元素的老大不等于该元素): 记录下该元素的老大到临时集合中 继续寻找该元素的老大的老大 遍历临时集合,将临时集合的各个元素的老大设置为找到的最终的老大(代表结点)
4.合并两个集合
如何合并两个集合,这并不难,将其中一个集合的代表结点作为合并后的新的集合的代表结点。
例如小a和小c所在的帮要合帮,那么可以将小b帮的代表结点b的老大设置为f,即f为新的合并的两个集合的代表结点。
leaderdict= { a的老大:b, b的老大:f, c的老大:f, d的老大:f, f的老大:f, }
5.应用
leetcode 朋友圈的个数
https://leetcode-cn.com/problems/friend-circles/
leetcode 等式方程的可满足性
https://leetcode-cn.com/problems/satisfiability-of-equality-equations/