leetcode 210. Course Schedule II(课程表2)

本文深入探讨了两种课程排序算法:深度优先搜索(DFS)和拓扑排序。通过实例讲解了如何利用这两种算法解决课程先修顺序问题,确保学生能够按照正确的顺序修读课程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

There are a total of n courses you have to take, labeled from 0 to n-1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.

There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.

Example 1:

Input: 2, [[1,0]]
Output: [0,1]
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished
course 0. So the correct course order is [0,1] .

以pair形式给出课程的先后顺序,让给出修完所有课程的整体顺序,如果是不可能完成的情况就返回空数组

思路:
建立有向图,题中[1,0]表示课程1之前要先修课程0,所以有向图中由0指向1,然后因为可能存在闭环,所以要保存每个node的访问状态,visiting,visited
如果正在访问的节点状态是visiting,就说明存在闭环,如果状态是visited,说明已经访问过,不需要再访问

DFS遍历每个节点,输出反向的遍历节点

    public int[] findOrder(int numCourses, int[][] prerequisites) {
        ArrayList<HashSet<Integer>> graph = new ArrayList<HashSet<Integer>>();
        ArrayList<Integer> state = new ArrayList<>(numCourses);
        
        ArrayList<Integer> ans = new ArrayList<>();
        int[] result = new int[numCourses];
        
        for(int i = 0; i < numCourses; i++) {
            graph.add(new HashSet<Integer>());
            state.add(0);
        }
        
        for(int i = 0; i < prerequisites.length; i++) {
            graph.get(prerequisites[i][1]).add(prerequisites[i][0]);
        }
        
        for(int i = 0; i < numCourses; i++) {
            if(dfs(i, graph, state, ans)) {
                return new int[]{};
            }
        }
        
        Collections.reverse(ans);
        for(int i = 0; i < ans.size(); i++) {
            result[i] = ans.get(i);
        }
        
        return result;
    }
    
    public boolean dfs(int cur, ArrayList<HashSet<Integer>> graph, 
                       ArrayList<Integer> state, ArrayList<Integer> ans) {
        if(state.get(cur) == 1) {
            return true;
        }
        if(state.get(cur) == 2) {
            return false;
        }
        
        state.set(cur, 1) ; //visting
        for(Integer num : graph.get(cur)) {
            if(dfs(num, graph, state, ans)) {
                return true;
            }
        }
        
        ans.add(cur);
        state.set(cur, 2); //visited
        
        return false;
        
    }

方法2:拓扑排序
先建立有向图的graph
找到入度为0的点,加入queue
取出queue中的节点,找到指向的节点,将指向节点的入度减1,当指向节点的入度变为0时,加入queue
反复操作,直到queue中没有节点

当有向图中存在环时,认为不可能完成课程,如何判断有向图中有没有环
拓扑排序中queue中处理的节点数==numCourses时,无环,反之有环

    public int[] findOrder(int numCourses, int[][] prerequisites) {
        if(numCourses <= 0 || prerequisites == null) {
            return new int[]{};
        }
        
        int n = numCourses;
        int[] inDegree = new int[n];
        boolean[] removed = new boolean[n];
        List<Integer>[] graph = new ArrayList[n];
        Queue<Integer> queue = new LinkedList<>();
        List<Integer> result = new ArrayList<>();
        int count = 0;
        
        for(int i = 0; i < n; i++) graph[i] = new ArrayList<Integer>();
        
        for(int[] order : prerequisites) {
            graph[order[1]].add(order[0]);
            inDegree[order[0]] ++;
        }
        
        for(int i = 0; i < n; i++) {
            if(inDegree[i] == 0) {
                queue.offer(i);
            }
        }
        
        while(queue.size() > 0) {
            int course = queue.poll();
            result.add(course);
            removed[course] = true;
            for(Integer nextCourse : graph[course]) {
                if(removed[nextCourse]) continue;
                inDegree[nextCourse]--;
                if(inDegree[nextCourse] == 0) queue.offer(nextCourse);
            }
            count ++;
        }
        
        if(count != n) {return new int[]{};}
        return result.stream().mapToInt(i->i).toArray();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值