返回

LeetCode 2192:有向无环图中的所有祖先(Python 代码)

后端

在有向无环图中查找节点的所有祖先

在数据结构和算法的世界中,有向无环图 (DAG) 是一种常见的结构。DAG 是由节点和有向边组成的,其中节点表示实体,边表示实体之间的关系。由于边具有方向性,因此 DAG 中不存在环路。

什么是祖先节点?

在 DAG 中,祖先节点是指直接或间接指向目标节点的节点。换句话说,如果从祖先节点沿着有向边可以到达目标节点,那么该节点就是目标节点的祖先。

使用 BFS 查找祖先节点

要找到目标节点的所有祖先,我们可以使用广度优先搜索 (BFS) 算法。BFS 是一种遍历图的算法,从一个起始节点开始,依次访问该节点的所有相邻节点,再访问相邻节点的相邻节点,以此类推。这种方式可以确保我们能找到所有与起始节点相连的节点。

Python 代码示例

以下是使用 Python 语言实现的 BFS 算法,用于查找目标节点的所有祖先:

def get_ancestors(graph, target):
    """
    找到目标节点的所有祖先

    参数:
    graph: 有向无环图,以邻接表的形式表示
    target: 目标节点

    返回:
    target 节点的所有祖先,以列表的形式表示
    """

    # 初始化祖先列表和队列
    ancestors = []
    queue = [target]

    # 循环遍历队列
    while queue:
        # 出队一个节点
        node = queue.pop(0)

        # 将节点添加到祖先列表中
        ancestors.append(node)

        # 将节点的所有相邻节点入队
        for neighbor in graph[node]:
            queue.append(neighbor)

    # 返回祖先列表
    return ancestors

复杂度分析

  • 时间复杂度:O(V + E),其中 V 是图中节点的数量,E 是图中边的数量。BFS 算法需要遍历所有与目标节点相连的节点,因此时间复杂度为 O(V + E)。
  • 空间复杂度:O(V),因为祖先列表最多包含图中所有节点。

示例

假设我们有一个 DAG,其邻接表表示为:

graph = {
    "A": ["B", "C"],
    "B": ["D", "E"],
    "C": ["F"],
    "D": ["G"],
    "E": ["H"],
    "F": [],
    "G": [],
    "H": [],
}

如果我们要找到节点 "G" 的所有祖先,我们可以使用以下代码:

ancestors = get_ancestors(graph, "G")

print(ancestors)

输出结果:

['A', 'B', 'D']

常见问题解答

1. 如何判断一个图是否是 DAG?

判断一个图是否是 DAG 可以使用拓扑排序算法。如果拓扑排序成功,则图是 DAG;否则,图不是 DAG。

2. BFS 和 DFS 算法有什么区别?

BFS 是广度优先搜索,从一个起始节点开始,依次访问该节点的所有相邻节点,再访问相邻节点的相邻节点,以此类推。DFS 是深度优先搜索,从一个起始节点开始,一直沿着一条路径深度搜索,直到无法继续搜索,再回溯到上一个节点继续搜索。

3. DAG 的应用场景有哪些?

DAG 在许多领域都有应用,例如:

  • 依赖关系管理
  • 事件调度
  • 图形渲染
  • 网络路由

4. 如何在 DAG 中查找环路?

在 DAG 中查找环路可以使用以下算法:

  • 拓扑排序算法
  • Tarjan 算法
  • Kosaraju 算法

5. 如何在 DAG 中找到最长路径?

在 DAG 中找到最长路径可以使用以下算法:

  • 拓扑排序算法
  • Bellman-Ford 算法
  • Floyd-Warshall 算法