代码随想录算法训练营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)
相关推荐
快去睡觉~2 小时前
力扣73:矩阵置零
算法·leetcode·矩阵
小欣加油2 小时前
leetcode 3 无重复字符的最长子串
c++·算法·leetcode
猿究院--王升5 小时前
jvm三色标记
java·jvm·算法
一车小面包5 小时前
逻辑回归 从0到1
算法·机器学习·逻辑回归
tt5555555555557 小时前
字符串与算法题详解:最长回文子串、IP 地址转换、字符串排序、蛇形矩阵与字符串加密
c++·算法·矩阵
元亓亓亓7 小时前
LeetCode热题100--101. 对称二叉树--简单
算法·leetcode·职场和发展
不会学习?8 小时前
算法03 归并分治
算法
NuyoahC8 小时前
笔试——Day43
c++·算法·笔试
2301_821919929 小时前
决策树8.19
算法·决策树·机器学习
秋难降9 小时前
别再用暴力排序了!大小顶堆让「取极值」效率飙升至 O (log n)
python·算法·排序算法