代码随想录算法训练营day70 | 108. 冗余连接、109. 冗余连接II

本次题目都来自卡码网

108. 冗余连接

无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树(即:只有一个根节点)。

  • 从前向后遍历每一条边(因为优先让前面的边连上),边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。
  • 如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,再加入这条边一定就出现环了。
python 复制代码
class UnionFind:
    def __init__(self, n):
        self.n = n
        self.father = [0] * (n + 1)

        for i in range(n + 1):
            self.father[i] = i

    def find(self, u):
        if u == self.father[u]:
            return u
        else:
            self.father[u] = self.find(self.father[u])
            return self.father[u]

    def join(self, u, v):
        u = self.find(u)
        v = self.find(v)
        if u == v:
            return
        else:
            self.father[u] = v

    def is_same(self, u, v):
        u = self.find(u)
        v = self.find(v)
        return u == v


if __name__ == '__main__':
    n = int(input())
    UnionFind = UnionFind(n)
    for i in range(n):
        s, t = map(int, input().strip().split())
        if UnionFind.is_same(s, t):
            print(str(s) + " " + str(t))
            exit()
        else:
            UnionFind.join(s, t)

109. 冗余连接II

1、先考虑节点有两个入度的情况,其中必定有一个是冗余的

2、如果不存在1的情况,则考虑环的情况

python 复制代码
class UnionFind:
    def __init__(self, n):
        self.n = n
        self.father = [0] * (n + 1)

        for i in range(n + 1):
            self.father[i] = i

    def find(self, u):
        if u == self.father[u]:
            return u
        else:
            self.father[u] = self.find(self.father[u])
            return self.father[u]

    def join(self, u, v):
        u = self.find(u)
        v = self.find(v)
        if u == v:
            return
        else:
            self.father[u] = v

    def is_same(self, u, v):
        u = self.find(u)
        v = self.find(v)
        return u == v


# 在有向图里找到删除的那条边,使其变成树
def getRemoveEdge(edges, n):
    union_find = UnionFind(n)  # 初始化并查集
    for i in range(union_find.n):  # 遍历所有的边
        if union_find.is_same(edges[i][0], edges[i][1]):  # 构成有向环了,就是要删除的边
            print(str(edges[i][0]) + " " + str(edges[i][1]))
        else:
            union_find.join(edges[i][0], edges[i][1])


# 删一条边之后判断是不是树
def isTreeAfterRemoveEdge(edges, deleteEdge, n):
    union_find = UnionFind(n)  # 初始化并查集
    for i in range(union_find.n):
        if i == deleteEdge:
            continue
        if union_find.is_same(edges[i][0], edges[i][1]):  # 构成有向环了,一定不是树
            return False
        else:
            union_find.join(edges[i][0], edges[i][1])
    return True


if __name__ == '__main__':
    n = int(input())
    edges = []
    inDegree = [0] * (n + 1)  # 记录节点入度
    for i in range(n):
        s, t = map(int, input().strip().split())
        inDegree[t] += 1
        edges.append((s, t))

    inDegree2 = []  # 记录入度为2的边(如果有的话就两条边)
    # 找入度为2的节点所对应的边,注意要倒序,因为优先删除最后出现的一条边
    for i in range(n - 1, -1, -1):
        if inDegree[edges[i][1]] == 2:
            inDegree2.append(i)
    if len(inDegree2) > 0:
        # 放在inDegree2里的边已经按照倒叙放的,所以这里就优先删inDegree2[0]这条边
        if isTreeAfterRemoveEdge(edges, inDegree2[0], n):
            print(str(edges[inDegree2[0]][0]) + " " + str(edges[inDegree2[0]][1]))
        else:
            print(str(edges[inDegree2[1]][0]) + " " + str(edges[inDegree2[1]][1]))
        exit()
    # 处理情况三
    # 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了
    getRemoveEdge(edges, n)
相关推荐
We་ct2 分钟前
LeetCode 33. 搜索旋转排序数组:O(log n)二分查找
前端·算法·leetcode·typescript·个人开发·二分·数组
智驱力人工智能3 分钟前
一盔一带AI抓拍系统能否破解非机动车执法取证难 骑行未戴头盔检测 电动车未戴头盔智能监测 摩托车头盔佩戴AI识别系统 边缘计算实时处理
人工智能·算法·yolo·目标检测·边缘计算
重生之我是Java开发战士7 分钟前
【优选算法】优先级队列:最后一块石头的重量,数据流中的第K大元素,前K个高频单词,数据流中的中位数
数据结构·算法·leetcode
智算菩萨9 分钟前
音频处理基础理论:从物理声波到数字信号完整知识体系
算法·机器学习·电脑·音视频
小高求学之路1 小时前
计算机视觉、YOLO算法模型训练、无人机监测人员密集自动识别
算法·yolo·计算机视觉
散峰而望1 小时前
【基础算法】剪枝与记忆化搜索:算法优化的双刃剑,效率倍增的实战指南
算法·机器学习·剪枝
m0_748873551 小时前
C++与Rust交互编程
开发语言·c++·算法
2401_891482179 小时前
多平台UI框架C++开发
开发语言·c++·算法
88号技师9 小时前
2026年3月中科院一区SCI-贝塞尔曲线优化算法Bezier curve-based optimization-附Matlab免费代码
开发语言·算法·matlab·优化算法
t198751289 小时前
三维点云最小二乘拟合MATLAB程序
开发语言·算法·matlab