leetcode 210. 课程表 II(拓扑排序)

题目链接
思路:拓扑排序(深搜)
拓扑排序的定义:给定一个包含n个节点的有向图G,我们给出它的节点编号的一种排序,如果满足,对于图G中的任何一条有向边(u,v),u都在排列中都出现在v的前面,那么就称该排列是图G的【拓扑排序】。
根据这个定义,可以得出两个结论:

  • 存在拓扑排序的图,肯定是有向无环图。即存在拓扑排序的图,肯定不能有环。
  • 一个有向无环图,他的拓扑排序可能有好多种,例如所有节点都没有边,那么任意的编号排列都是一种拓扑排序。

这个题目的意思就是求一个图的拓扑排序,前提是如果存在的话。

首先:将题目给的图,用邻接链表存储起来。
举例:numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
那么邻接链表如下图:
在这里插入图片描述
[u,v]:表示u到v存在一条有向边,但是我们遍历的时候是先访问最后的节点的。所以这里才表示为u到v的有向边。
我们将图存储起来后。
使用一个标志记录当前图是否有环,有环的判断就是指从某个点出发,经过一系列的遍历,又回到了这个点,如果有环,那么就不存在拓扑排序。
使用一个数组标志某个点是否被遍历过,如果遍历过,那么就不再遍历。
并且每个点有三种状态。(正在遍历中,遍历结束,还未遍历)。
代码:

class Solution {
    List<List<Integer>> list = null;
    
    //1搜索中  2 已经搜索过  0 未搜索
    int[] visited = null;

    //numCourses-1;
    int[] res = null;
    int index = -1;


    //是否有环
    boolean valid = true;

    public int[] findOrder(int numCourses, int[][] prerequisites) {
        
        if(numCourses==1){
            return new int[]{0};
        }

        visited = new int[numCourses];
        list = new ArrayList<>(numCourses);
        res=new int[numCourses];
        index = numCourses-1;

        for(int i=0; i<numCourses; i++){
            list.add(new ArrayList<>());
        }

        //邻接链表存储
        for(int[] pre : prerequisites){
            list.get(pre[1]).add(pre[0]);
        }

        //挑选 没被搜索过的节点进行dfs
        for(int i=0;i<numCourses;i++){
            if(visited[i]==0){
                dfs(i);
            }
        }
        
        if(!valid){
            //说明有环,有环肯定不行
            return new int[]{};
        }
        return res;
    }

    private void dfs(int start){
        if(!valid){
            //有环直接返回
            return;
        }
        if(visited[start]==1){
            //形成了环
            valid = false;
            return;
        }
        //将当前节点的状态改为正在搜索
        visited[start] = 1;

        //取出该节点的链表
        List<Integer> seqr = list.get(start);

        //搜索该链表中的节点
        for(int i=0;i<seqr.size();i++){
            if(visited[seqr.get(i)]==2){
                //已经被搜索过了就不搜索了
                continue;
            }

            dfs(seqr.get(i));
        }

        //将当前节点改为搜索完成
        visited[start] = 2;
        //加入答案
        res[index--] = start;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值