返回

LeetCode 685:冗余连接 II

前端

引言

探索数据结构和图论的奥妙,我们来到 LeetCode 的第 685 题——冗余连接 II。这是一个关于树的有趣问题,考察了我们识别和删除冗余边以重建唯一树结构的能力。在这篇技术指南中,我们将深入剖析问题的核心,提供清晰的步骤和示例代码,引导您走向解决方案。

理解问题

LeetCode 685 的题目如下:

在本问题中,有根树指满足以下条件的 有向 图。

该树只有一个根节点,所有其他节点都是该根节点的后继。
该树除了根节点之外的每一个节点都有且只有一个父节点,而根节点没有父节点。

该问题给定一个由边构成的数组,要求我们找到并返回该图中冗余的边。冗余边是指在删除后仍保持图的树结构的边。

算法概述

解决此问题的核心思想是利用并查集数据结构。并查集是一种高效的数据结构,用于维护一组不相交集合的集合。在我们的情况下,集合代表节点,而集合的并集代表与该节点相连的节点。

算法流程如下:

  1. 初始化并查集: 为每个节点创建一个单元素集合。
  2. 处理边: 对于给定的每条边,找到其两端的节点所属的集合。
  3. 判断是否冗余: 如果这两个节点属于同一个集合,则该边是冗余边。
  4. 合并集合: 如果该边不是冗余边,则合并这两个节点所属的集合。
  5. 查找根节点: 对于每个节点,找到其所属集合的根节点。
  6. 输出冗余边: 根节点相同的两条边是冗余边。

示例代码

def findRedundantDirectedConnection(edges):
    # 初始化并查集
    parent = [i for i in range(len(edges) + 1)]
    # 记录节点指向的父节点
    指向父节点 = {}

    for edge in edges:
        u, v = edge
        # 如果节点 v 已经有父节点,则这条边是冗余边
        if v in 指向父节点:
            return [指向父节点[v], v]
        # 否则,将节点 v 的父节点设为节点 u
        指向父节点[v] = u

    # 找出指向根节点的边
    指向根节点 = {}
    for edge in edges:
        u, v = edge
        # 如果节点 u 是根节点
        if parent[u] == u:
            # 如果节点 u 已经指向过根节点,则返回这条边
            if u in 指向根节点:
                return [指向根节点[u], u]
            # 否则,将节点 u 指向根节点
            指向根节点[u] = v

    # 返回指向根节点的边
    return list(指向根节点.items())[0]

复杂度分析

  • 时间复杂度:O(N),其中 N 是图中的节点数。
  • 空间复杂度:O(N),其中 N 是图中的节点数。

结论

LeetCode 685:冗余连接 II 是一道经典的树图论问题。通过理解问题的本质并利用并查集数据结构,我们可以高效地找到并返回冗余边。掌握这些概念和算法不仅对于解决 LeetCode 问题至关重要,而且对于任何处理树形数据的应用程序也同样重要。