684 冗余连接

本文解析了LeetCode题目684中如何使用并查集数据结构来判断新添加边是否会形成闭环,介绍了并查集的基本概念、操作以及如何在代码中实现。通过实例展示了如何合并连通分量和判断连通性,是理解并查集在图论应用中的关键技巧。
摘要由CSDN通过智能技术生成

684 冗余连接

1.题目描述

leetcode 684 就是多加一条边就形成闭环了,删掉最后一条边就不是闭环了,

2.代码如下:

class Solution:
    def findRedundantConnection(self, edges: List[List[int]]) -> List[int]:
        # 节点的个数
        nodesCount = len(edges)
        # 边的个数,定义一个节点list
        # list(5),产生一个0-4的list
        parent = list(range(nodesCount + 1))

        # 查找节点的父节点,!!!并且将所有一个联通结合的父节点都设置为了最后一个点
        def find(index: int) -> int:
            # 递归查找父节点,直到他是自己的
            if parent[index] != index:
                parent[index] = find(parent[index])
            return parent[index]
        
        # 合并两个连通分量,使得index1节点的父节点设置为index2的父节点
        def union(index1: int, index2: int):
            parent[find(index1)] = find(index2)

        for node1, node2 in edges:
            # 如果两个节点的父节点不同,即连通分量不同,则合并
            if find(node1) != find(node2):
                union(node1, node2)
            else:
            # 如果两个节点的父节点,即连通分量相同,则返回 
                return [node1, node2]
        
        return []

3.解释

该题就是通过判断新加入的一条边的两个端点是否已经连通,连通在并查集中就是判断两个点是否在一个连通分量中,那么就得将已有的节点合并成连通分量,若新加入的点若是连通则加入集合中(即将该点的父节点设置为已经在连通分量那一点的父节点)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xFE8QHuG-1610610450493)(C:\Users\70902\AppData\Roaming\Typora\typora-user-images\image-20210114144609666.png)]

4.并查集相关

并查集逻辑上是森林,我们可以选出一个根节点作为代表,其他子结点指向根结点表示都在同一片森林中。在这里,并不关心结点的子结点是谁,只关心父结点是谁,所以物理上可以简单用python的列表来表示并查集,列表的下标表示结点,列表元素的值表示父结点。

并查集一般包括初始化,查找根节点,合并,判断是否在一个树中。

class UnionFind(object):
    # 并查集初始化
    # 初始化的作用就是在list中用一种特殊的方式表示初始元素每一个都在一个单独的集合,即父节点都不一样,即list中的元素都不一样
    def __init__(self, n):
        # 并查集每个单独的元素自成一个元素
        # 0 - n
        self.uf = [i for i in range(n + 1)]
        # 或者用-1表示集合的根节点
        self.uf = [-1 for i in range(n + 1)]
        self.sets_count = n
    
    def find(self, p):
        while self.uf[p] >= 0:
            p = self.uf[p]
        return p
    # 查找的过程中可以路径压缩,减小下一次查找的复杂度
    #路径压缩:在子节点的查找过程中,将子节点的父节点统统改为根节点
    def find(self, p):
       #尾递归
        if self.uf[p] < 0:
            return p
        self.uf[p] = self.find(self.uf[p])
        return self.uf[p]
    
    def find(self, p):
        #"""查找p的根结点(祖先)"""
        r = p                                   # 初始p
        while self.uf[p] > 0:
            p = self.uf[p]
        while r != p:                           # 路径压缩, 把搜索下来的结点祖先全指向根结点
            self.uf[r], r = p, self.uf[r]
            # 相当于
            self.uf[r] = p
            r = self.uf[r]
        return p    
    
    # 有向图连通
    def union(self, p, q):
         #"""连通p,q 让q指向p"""
        proot = self.find(p)
        qroot = self.find(q)
        if proot == qroot:
            return
        elif self.uf[proot] > self.uf[qroot]:   # 负数比较, 左边规模更小
            self.uf[qroot] += self.uf[proot]
            self.uf[proot] = qroot
        else:
            # 其实这里有点不太明白为什么规模相加是这么加的……每一个集合的uf[proot]根节点的父节点存在是这个集合的总数?
            self.uf[proot] += self.uf[qroot]    # 规模相加
            self.uf[qroot] = proot
        self.sets_count -= 1                    # 连通后集合总数减一
        
        
    def is_connected(self, p, q):
        return self.find(p) == self.find(q)

5.刷题Tips

def is_connected(self, p, q):
    return self.find(p) == self.find(q)

## 5.刷题Tips

无向图连通性 考虑 并查集 有向图依赖性 考虑 深度广度优先 拓扑排序
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值