【图论】B002_课程表 II(判环 | 入度统计)

一、题目描述

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.

Input: 4, [[1,0],[2,0],[3,1],[3,2]]
Output: [0,1,2,3] or [0,2,1,3]
Explanation: There are a total of 4 courses to take. 
To take course 3 you should have finished both     
courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. 
So one correct course order is [0,1,2,3]. 
Another correct ordering is [0,2,1,3] .

二、题解

和 课程表 I 一样,这一题需要得到课程学习路线。

方法一:bfs

  • 建图,然后统计每一个课程的入度,即先修课的数量。
  • 入度为 0 的结点入队,表示先修这些课程。
  • bfs 遍历图的结果就是课程的学习路线了。
public int[] findOrder(int numCourses, int[][] edges) {
    List<Integer> order = new ArrayList<>();
    List<List<Integer>> graph = new ArrayList<>();
    for (int i = 0; i < numCourses; i++) {
        graph.add(new LinkedList<>());
    }
    int[] in = new int[numCourses];
    for (int[] edge : edges) {
        in[edge[0]]++;
        graph.get(edge[1]).add(edge[0]);
    }
    Queue<Integer> q = new LinkedList<>();
    for (int i = 0; i < numCourses; i++) {
        if (in[i] == 0)
            q.add(i);
    }
    while (!q.isEmpty()) {
        int pre = q.poll();
        order.add(pre);
        for (int toTake : graph.get(pre)) {
            in[toTake]--;
            if (in[toTake] == 0) {
                q.add(toTake);
            }
        }
    }
    if (order.size() < numCourses)
        return new int[]{};
    int[] res = new int[numCourses];
        for (int i = 0; i < order.size(); i++) {
        res[i] = order.get(i);
    }
    return res;
}

复杂度分析

  • 时间复杂度: O ( e + v ) O(e+v) ,e 为边数,v 为顶点。
  • 空间复杂度: O ( e + v ) O(e+v)

方法二:dfs + 逆序

和 课程表 I 的做法一样,修改几个点即可。

  • 如果存在环,返回空数组。
  • 否则,返回 order 的逆序数组。
    • 因为 dfs 一直遍历完到某一个结点的最后才会停止,所以,我们学的课是逆序的。
List<Integer> order;
List<List<Integer>> graph;
boolean[] vised, vising;
public int[] findOrder(int numCourses, int[][] edges) {
    order = new ArrayList<>();
    graph = new ArrayList<>();
    vised = new boolean[numCourses];
    vising = new boolean[numCourses];
    
    for (int i = 0; i < numCourses; i++) {
        graph.add(new LinkedList<>());
    }
    for (int[] edge : edges) {
        graph.get(edge[1]).add(edge[0]);
    }
    for (int i = 0; i < numCourses; i++) {
        if (dfs(i))
            return new int[] {};
    }
    Collections.reverse(order);
    int[] res = new int[numCourses];
    for (int i = 0; i < order.size(); i++) {
        res[i] = order.get(i);
    }
    return res;
}
private boolean dfs(int i) {
    if (vising[i])  return true;
    if (vised[i])   return false;
    vising[i] = true;
    for (int neigh : graph.get(i)) {
        if (dfs(neigh))
            return false;
    }
    order.add(i);
    vising[i] = false;
    vised[i] = true;
    return false;
}

复杂度分析

  • 时间复杂度: O ( e + v ) O(e+v) ,e 为边数,v 为顶点。
  • 空间复杂度: O ( e + v ) O(e+v)
发布了691 篇原创文章 · 获赞 151 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/105449164