拓扑排序--有向无环图中一个节点的所有祖先

题目描述

给你一个正整数 n ,它表示一个 有向无环图 中节点的数目,节点编号为 0 到 n - 1 (包括两者)。

给你一个二维整数数组 edges ,其中 edges[i] = [fromi, toi] 表示图中一条从 fromi 到 toi 的单向边。

请你返回一个数组 answer,其中 answer[i]是第 i 个节点的所有 祖先 ,这些祖先节点 升序 排序。

如果 u 通过一系列边,能够到达 v ,那么我们称节点 u 是节点 v 的 祖先 节点。

示例 1:

输入:n = 8, edgeList = [[0,3],[0,4],[1,3],[2,4],[2,7],[3,5],[3,6],[3,7],[4,6]]
输出:[[],[],[],[0,1],[0,2],[0,1,3],[0,1,2,3,4],[0,1,2,3]]
解释:
上图为输入所对应的图。
- 节点 0 ,1 和 2 没有任何祖先。
- 节点 3 有 2 个祖先 0 和 1 。
- 节点 4 有 2 个祖先 0 和 2 。
- 节点 5 有 3 个祖先 0 ,1 和 3 。
- 节点 6 有 5 个祖先 0 ,1 ,2 ,3 和 4 。
- 节点 7 有 4 个祖先 0 ,1 ,2 和 3 。

示例 2:

输入:n = 5, edgeList = [[0,1],[0,2],[0,3],[0,4],[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
输出:[[],[0],[0,1],[0,1,2],[0,1,2,3]]
解释:
上图为输入所对应的图。
- 节点 0 没有任何祖先。
- 节点 1 有 1 个祖先 0 。
- 节点 2 有 2 个祖先 0 和 1 。
- 节点 3 有 3 个祖先 0 ,1 和 2 。
- 节点 4 有 4 个祖先 0 ,1 ,2 和 3 。

提示:

  • 1 <= n <= 1000
  • 0 <= edges.length <= min(2000, n * (n - 1) / 2)
  • edges[i].length == 2
  • 0 <= fromi, toi <= n - 1
  • fromi != toi
  • 图中不会有重边。
  • 图是 有向 且 无环 的。

1. 思路

有向无环图中,每个节点的所有祖先节点集合即为该节点所有父节点(即有一条直接指向该节点的有向边的节点)的本身及其祖先节点组成集合的并集。

如果我们按照拓扑排序的顺序来遍历每个节点并计算祖先节点集合,那么遍历到某个节点时,其所有父节点的祖先节点集合都已计算完成,我们就可以直接对这些集合加上父节点本身取并集得到该节点的所有祖先节点。这一「取并集」的过程等价于在拓扑排序的过程中用每个节点的祖先集合更新每个节点所有子节点的祖先集合。

具体地,我们用哈希表数组 anc 来表示每个节点的祖先节点集合,用 e 以邻接表形式存储每个节点的所有出边,并用数组 indeg 来计算每个结点的入度。

我们可以用广度优先搜索的方法求解拓扑排序。首先我们遍历 edges 数组预处理邻接表 e 和入度表 indeg,并将所有入度为 0 的节点加入广度优先搜索队列 q。此时队列里的元素对应的祖先节点集合均为空集,且都已经更新完成。

在遍历到节点 u 时,我们首先遍历所有通过出边相邻的子节点 v,此时根据定义 u 一定是 v 的父节点,且根据拓扑序,u 的祖先节点集合 anc[u] 已经更新完毕。因此我们将 anc[u] 的所有元素和 u 加入至 anc[v] 中,并将 v 的入度 indeg[v] 减去 1。此时,如果 indeg[v]=0,则说明 anc[v] 已经更新完成,此时我们将 v 加入队列。

最终,我们需要利用嵌套数组 res 将 anc 中的每个哈希集合对应地转化为升序排序后的数组,此时 res 即为待求的升序排序的每个节点的所有祖先。我们返回 res作为答案即可。

2. 代码

public List<List<Integer>> getAncestors(int n, int[][] edges) {Set<Integer>[] anc = new Set[n];   // 存储每个节点祖先的辅助数组for (int i = 0; i < n; ++i) {anc[i] = new HashSet<Integer>();}List<Integer>[] e = new List[n];   // 邻接表for (int i = 0; i < n; ++i) {e[i] = new ArrayList<Integer>();}int[] indeg = new int[n];   // 入度表// 预处理for (int[] edge : edges) {e[edge[0]].add(edge[1]);++indeg[edge[1]];}// 广度优先搜索求解拓扑排序Queue<Integer> q = new ArrayDeque<Integer>();for (int i = 0; i < n; ++i) {if (indeg[i] == 0) {q.offer(i);}}while (!q.isEmpty()) {int u = q.poll();for (int v : e[u]) {// 更新子节点的祖先哈希表anc[v].add(u);for (int i : anc[u]) {anc[v].add(i);}--indeg[v];if (indeg[v] == 0) {q.offer(v);}}}// 转化为答案数组List<List<Integer>> res = new ArrayList<List<Integer>>();for (int i = 0; i < n; ++i) {res.add(new ArrayList<Integer>());for (int j : anc[i]) {res.get(i).add(j);}Collections.sort(res.get(i));}return res;}

3. 参考题目

. - 力扣(LeetCode)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/593799.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OAuth 2.0 的四种方式

RFC 6749 OAuth 2.0 的标准是 RFC 6749 文件。该文件先解释了 OAuth 是什么。 OAuth 引入了一个授权层&#xff0c;用来分离两种不同的角色&#xff1a;客户端和资源所有者。…资源所有者同意以后&#xff0c;资源服务器可以向客户端颁发令牌。客户端通过令牌&#xff0c;去请…

K8S - Deployment 的版本回滚

当前状态 先看deployment rootk8s-master:~# kubectl get deploy -o wide --show-labels NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES …

Xen Server 8 Install

Xen Sevrer 前言 XenServer&#xff08;以前称为 Citrix Hypervisor&#xff09;是业界领先的平台&#xff0c;实现了经济高效的桌面、服务器和云虚拟化基础结构。XenServer 支持任意规模或类型的组织整合计算资源&#xff0c;以及将计算资源转换为虚拟工作负载&#xff0c;从…

代码随想录|Day32|动态规划01|509.斐波那契数列、70.爬楼梯、746.使用最小花费爬楼梯

509.斐波那契数列 动规五步曲&#xff1a; 确定 dp[i] 含义&#xff1a;第 i 个斐波那契数值为 dp[i]递推公式&#xff1a;dp[i] dp[i - 1] dp[i - 2]dp数组初始化&#xff1a;dp[0] dp[1] 1遍历顺序&#xff1a;从前向后打印dp数组 class Solution:def fib(self, n: int) …

【拓扑空间】示例及详解2

设A是X的一个子集&#xff0c; 内点、邻域&#xff1a;&#xff0c;则x是A的一个内点&#xff0c;A是x的一个领域 内部&#xff1a;A的所有的内点的集合称为A的内部&#xff0c;记 例1 证明&#xff1a; Proof: 例2 证明&#xff1a;是包含在A中的所有开集的并集&#xff0c…

Waifu2x:使用深度卷积神经网络的动漫风格艺术的图像超分辨率

Github网址&#xff1a;nagadomi/waifu2x&#xff1a;动漫风格艺术的图像超分辨率 (github.com) 该项目主要讲述的是如何利用预训练的深度学习模型来达到无损扩大收缩和去噪&#xff0c;对于一般训练图像的小伙伴应该很清晰图像经常要通过resize操作固定大小&#xff0c;然后c…

spring事务那些事

实际工作中还会面临千奇百怪的问题&#xff0c;看下面返个例子&#xff08;注意MySql数据库测试&#xff09;&#xff1a; //1.hello1Service 调用 hello2Service Transactional(propagation Propagation.REQUIRED,rollbackFor Exception.class) public void doUpdate() {//…

【代码随想录】链表

203. 移除链表元素 // public class ListNode { // int val; // ListNode next; // ListNode() {} // ListNode(int val) { this.val val; } // ListNode(int val, ListNode next) { this.val val; this.next next;} // }class Solution {public ListNo…

Linux 安装系统可视化监控工具 Netdata

目录 About 监控工具 NetdataLinux 系统安装 Netdata关于 openEuler1、查看内核信息2、查看主机信息3、查看 dnf 包管理器的版本 Netdata 安装1、更新系统环境相关 rpm 包2、查看 netdata 包信息3、安装 netdata 包4、编辑 netdata.conf 配置5、启动 netdata 服务6、查看 netda…

TCP的十个重要的机制

注&#xff1a;TCP不是只有十个机制 TCP 可靠传输是tcp最为重要的核心&#xff08;初心&#xff09; 可靠传输&#xff0c;并不是发送方把数据能够100%的传输给接收方 而是退而求其次 让发送方发送出去数据之后&#xff0c;能够知道接收方是否收到数据。 一但发现对方没有…

FAS-Net

感想 图的下标弄不好&#xff0c;且作者未提供代码。AAAI的质量也就这样吧

基于Springboot + vue + mysql 游戏分享管理系统 (含源码)

目录 &#x1f4da; 前言 &#x1f4d1;摘要 &#x1f4d1;系统架构 &#x1f4da; 系统架构设计 &#x1f4da; 数据库设计 &#x1f4ac; 管理员功能需求E/R图 &#x1f4ac; 用户功能需求E/R图 &#x1f4ac; 游戏文章E/R图 &#x1f4ac; 用户E/R图 &#x1f4da; 系…