🚩传送门:力扣题目

题目

给你一个正整数 [LC]2192. 有向无环图中一个节点的所有祖先 - 图1 ,它表示一个 有向无环图 中节点的数目,节点编号为 [LC]2192. 有向无环图中一个节点的所有祖先 - 图2[LC]2192. 有向无环图中一个节点的所有祖先 - 图3 (包括两者)。

给你一个二维整数数组 [LC]2192. 有向无环图中一个节点的所有祖先 - 图4 ,其中 [LC]2192. 有向无环图中一个节点的所有祖先 - 图5 表示图中一条从 [LC]2192. 有向无环图中一个节点的所有祖先 - 图6[LC]2192. 有向无环图中一个节点的所有祖先 - 图7 的单向边。

请你返回一个数组 [LC]2192. 有向无环图中一个节点的所有祖先 - 图8,其中[LC]2192. 有向无环图中一个节点的所有祖先 - 图9是第 [LC]2192. 有向无环图中一个节点的所有祖先 - 图10 个节点的 所有祖先 ,这些祖先节点 升序 排序。

如果 [LC]2192. 有向无环图中一个节点的所有祖先 - 图11 通过一系列边,能够到达 [LC]2192. 有向无环图中一个节点的所有祖先 - 图12 ,那么我们称节点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图13 是节点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图14祖先 节点。

示例 1:
[LC]2192. 有向无环图中一个节点的所有祖先 - 图15

输入: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 。

解题思路:拓扑排序

广度搜索

  • [LC]2192. 有向无环图中一个节点的所有祖先 - 图16数组:记录所有结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图17 的入度,结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图18入度为[LC]2192. 有向无环图中一个节点的所有祖先 - 图19时需要入队
  • [LC]2192. 有向无环图中一个节点的所有祖先 - 图20数组:记录所有结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图21 的直系父亲结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图22
  • [LC]2192. 有向无环图中一个节点的所有祖先 - 图23数组:记录所有结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图24 的直系孩子结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图25

从队列中取出每一个入度为[LC]2192. 有向无环图中一个节点的所有祖先 - 图26的结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图27 ,注意此时结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图28 的直系父亲结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图29 一定已经遍历完成,且计算结果保存在[LC]2192. 有向无环图中一个节点的所有祖先 - 图30数组中,所以只要在[LC]2192. 有向无环图中一个节点的所有祖先 - 图31数组中取出结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图32的每一个直系父亲结点 [LC]2192. 有向无环图中一个节点的所有祖先 - 图33 ,将[LC]2192. 有向无环图中一个节点的所有祖先 - 图34加入结果集[LC]2192. 有向无环图中一个节点的所有祖先 - 图35,并将[LC]2192. 有向无环图中一个节点的所有祖先 - 图36代表 [LC]2192. 有向无环图中一个节点的所有祖先 - 图37 的所有祖先)的结果也加入到[LC]2192. 有向无环图中一个节点的所有祖先 - 图38

最后对 [LC]2192. 有向无环图中一个节点的所有祖先 - 图39进行去重、排序 。插入[LC]2192. 有向无环图中一个节点的所有祖先 - 图40中即可,有点麻烦处理,需要先删除[LC]2192. 有向无环图中一个节点的所有祖先 - 图41处的空数组,在将[LC]2192. 有向无环图中一个节点的所有祖先 - 图42插入[LC]2192. 有向无环图中一个节点的所有祖先 - 图43

我的代码

  1. class Solution {
  2. public static List<List<Integer>> getAncestors(int n, int[][] edges) {
  3. int[]inedges=new int[n]; // 入度数组
  4. List<List<Integer>>v_u_edges=new ArrayList<>(); // 记录所有v的直系父亲结点u
  5. List<List<Integer>>u_v_edges=new ArrayList<>(); // 记录所以u的直系孩子结点v
  6. List<List<Integer>>res=new ArrayList<>();
  7. // 为数组分配空间
  8. for (int i = 0; i < n; i++) {
  9. res.add(new ArrayList<>());
  10. v_u_edges.add(new ArrayList<>());
  11. u_v_edges.add(new ArrayList<>());
  12. }
  13. // 遍历 edges 记录所有v的入度,v 的直系父亲结点 u,u的直系孩子结点
  14. for (int i = 0; i < edges.length; i++) {
  15. inedges[edges[i][1]]++;
  16. u_v_edges.get(edges[i][0]).add(edges[i][1]);// 记录u的孩子v
  17. v_u_edges.get(edges[i][1]).add(edges[i][0]);// 记录v的父亲u
  18. }
  19. // 将入度为0的入队
  20. LinkedList<Integer>queue=new LinkedList<>();
  21. for (int i = 0; i < n; i++) {
  22. if (inedges[i]==0) {
  23. queue.addLast(i);
  24. }
  25. }
  26. while(!queue.isEmpty()){
  27. int v=queue.pollFirst();
  28. // 添加 v 父亲
  29. HashSet<Integer>set=new HashSet<>();
  30. for(int u:v_u_edges.get(v)){
  31. set.add(u); // 直系父亲
  32. // 父亲u的已经计算完成在 res 中的结果集拿过来
  33. for (int uu :res.get(u)) {
  34. set.add(uu);
  35. }
  36. }
  37. // 去重
  38. List<Integer>temp=new ArrayList<>();
  39. for (Integer u:set){
  40. temp.add(u);
  41. }
  42. // 排序
  43. temp.sort(new Comparator<Integer>() {
  44. @Override
  45. public int compare(Integer o1, Integer o2) {
  46. return o1-o2;
  47. }
  48. });
  49. // 先删除再插入
  50. res.remove(v);
  51. res.add(v,temp);
  52. // 此时 v 遍历完成,还需要将 v 的所有孩子的入度-1,当入度为0时入队
  53. for(int vv:u_v_edges.get(v)){
  54. inedges[vv]--;
  55. if(inedges[vv]==0)queue.addLast(vv);
  56. }
  57. }
  58. return res;
  59. }
  60. }