算法笔记--并查集&优化--Leetcode1319. 连通网络的操作次

    最近在学习算法,虽然看书觉得理论都知道,可是一去刷题就不会,不知道咋用,所以打算每刷一题,便将其记录下来,用于以后的自我回顾。这次选择从并查集(Leetcode1319)开始

  • 并查集通俗概念

     在网上可以搜出一堆很专业术语,这里写下我自己的理解:即将彼此孤立的点先划分为单个集合,如果某两点之间有相同的关系,就放到一个集合里。就像地里一堆水果。是苹果一篮,梨一篮。如果在放大一些,梨和苹果又是可以

构成一个集合,都是果树。这里提完了并,在说下查的过程,就是任取一个点,通过它可以找到它所属最终的根,即你这果子最后是属于哪个果树。如果我们都是苹果,但之前没有我们没划分到一个集合里,那么我们合并,否则直接返回。如果没有合并的条件,是不会执行这个并操作的

  • 并查集通用代码段
1. 初始化

每个点且赋值 -1 ,看题解的python代码段也可以使用list(range(n))初始化为s[n]=[0,1,2].按序递增,差别就在后面find函数的判断里,后续代码将采用一致为-1作每个节点根节点的S[x]值

s = [-1 for _ in range(n)]
2. Find 函数:查找目标结点的根结点
def find(x):
    while s[x]>=0:
        x=s[x]
    return x
    

  如果你这个结点有进行合并过操作,则s[x]的值为其父结点的下标值,那将恒为正,只要满足正值,表示并未找到真正的根节点,此时一直找下去,直至-1的位置

此方法在树并不是很合理的方式,如所有的节点都连成了一条线,将导致时间有点长,为此将其代码进行了优化

  Find优化版—压缩路径:
  • 逻辑是第一次循环先找目标点的根节点,在第二次循环依次将目标节点及其父节点都直接挂到根目录下,这样达到路径压缩目的,如果下次找这条路径上的点,都能一下从根节点找到

如图:

def find(x):
    root=x
    while(self.parent[root]>=0):
        root=self.parent[root]
    while(x!=root):
        t=self.parent[x]
        self.parent[x]=root
        x=t
    return root

这里首先将x给root是为了防止第一次循环改变x值,所以当真正找到了root就可以和x在第二次使用判定是否已经在root下

3. Union函数 

只要函数具有关联能放到一个集合里,就直接将node1作为node2的根节点

def unin(self,node1,node2):
    s[node2]=node1   

上面这段代码会出现某种问题,如果大树挂到小树上会出现高度增加,但是为了维持树的高度不变,那可以将小树挂到大树上,这样树的高不变,只是宽度增加

 Union优化版—小树挂大树:

def Union(self,node1,node2): ##采用子结点小的放到大的,即让树横着长
    if node1==node2:
        return      
    rootx=self.find(node1)
    rooty=self.find(node2)
    if self.s[rooty]>self.s[rootx]:
       self.s[rootx]+=self.s[rooty]
       self.s[rooty]=rootx
    else:
       self.s[rooty]+=self.s[rootx]
       self.s[rootx]=rooty
        
  • Leetcode1319
class UnionFind:
    def __init__(self, n: int):
        self.parent = [-1 for _ in range(n)]
        self.setCount = n
    def find(self,x): ##采用路径压缩,将其查找的的父节点直至根,都直接放到根结点下面
        root=x
        while(self.parent[root]>=0):
            root=self.parent[root]
        while(x!=root):
            t=self.parent[x]
            self.parent[x]=root
            x=t
        return root

    def unin(self,x,y): ##采用子结点小的放到大的,即让树横着长
        rootx=self.find(x)
        rooty=self.find(y)
        if rootx == rooty:
            return False
        if self.parent[rooty]>self.parent[rootx]:
            self.parent[rootx]+=self.parent[rooty]
            self.parent[rooty]=rootx
            self.setCount -= 1
        else:
            self.parent[rooty]+=self.parent[rootx]
            self.parent[rootx]=rooty
            self.setCount -= 1
        return True
        
class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections) <n-1:
            return -1     
        uf = UnionFind(n)
        for x, y in connections:
            uf.unin(x,y)
        return uf.setCount -1

  • 13
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值