leetcode 802 找到最终的安全状态——反向图(链式前向星存图方式)+拓扑排序

题目

在有向图中,以某个节点为起始节点,从该点出发,每一步沿着图中的一条有向边行走。如果到达的节点是终点(即它没有连出的有向边),则停止。
对于一个起始节点,如果从该节点出发,无论每一步选择沿哪条有向边行走,最后必然在有限步内到达终点,则将该起始节点称作是 安全 的。
返回一个由图中所有安全的起始节点组成的数组作为答案。答案数组中的元素应当按 升序 排列。
该有向图有 n 个节点,按 0 到 n - 1 编号,其中 n 是 graph 的节点数。图以下述形式给出:graph[i] 是编号 j 节点的一个列表,满足 (i, j) 是图的一条有向边。

  • 输入输出样例
    在这里插入图片描述

思路分析(反向图(链式前向星存图方式)+拓扑排序)

对拓扑排序不了解的小伙伴,可以看看拓扑排序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码:

class Solution {
    //定义节点的数量和边的数量,N是点的最大的数量,M定义的是最大的边数
    int N=(int)1e4+10,M=4*N;
    int idx=0;  //idx用来对边进行编号
    //其中he[i]存储的是同一起点的边的集合的头结点(即第一条边对应的索引位置,这些集合以链的形式存储)
    //比如h[1]=2; 代表的是以1为起点的第一条边对应的索引位置是2,
    //e:代表访问某一条边指向的节点,e[2]=6表示索引为2的这条边指向的是6
    //ne[i]:由于相同的起点的边集合是以链表的形式存储,用于找到下一条边
    int[] he=new int[N],e=new int[M],ne=new int[M];
    int[] cnts=new int[N];  //统计每个节点的,入度
    //用于存图,将图存入上述的数组中去
    void add(int a,int b){
        e[idx]=b;
        ne[idx]=he[a];
        he[a]=idx;
        idx++;
    }
    public List<Integer> eventualSafeNodes(int[][] g) {
        int n=g.length;
        //首先将he数组全部用-1进行填充
        Arrays.fill(he,-1);
        //反向存图,并且统计反向后节点入度
        for(int i=0;i<n;++i){
            for(int j:g[i]){
                add(j,i);
                cnts[i]++;
            }
        }
        //BFS求反向图的拓扑排序
        Deque<Integer> d=new ArrayDeque<>();
        //先遍历一轮,将入度为0的结点存入队列
        for(int i=0;i<n;++i){
            if(cnts[i]==0)d.addLast(i);
        }
        while(!d.isEmpty()){
            int poll=d.pollFirst();
            //此时要将入读为0的结点,从图中割离,并且要处理相关联的结点
            for (int i=he[poll];i!=-1;i=ne[i]){
                int j=e[i];
                if(--cnts[j]==0)d.addLast(j);
            }
        }
        //遍历答案:如果某个结点出现在了拓扑排序中,就说明其进入过队列,入度为0
        List<Integer>  ans=new ArrayList<>();
        for(int i=0;i<n;++i){
            if(cnts[i]==0) ans.add(i);
        }
        return ans;
    }
}
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西瓜程序设计

您的打赏将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值