Course Schedule II

update Jul 20, 2017 12:10

lintcodearrow-up-right LeetCodearrow-up-right

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

Given n = 2, prerequisites = [[1,0]]
Return [0,1]

Given n = 4, prerequisites = [1,0],[2,0],[3,1],[3,2]]
Return [0,1,2,3] or [0,2,1,3]

Basic Idea:

其实就是求topological sort,如果无法sort,返回空列表。注意实现细节,python code is more concise than Java.

Java Code:

    public class Solution {
        /**
         * @param numCourses a total of n courses
         * @param prerequisites a list of prerequisite pairs
         * @return the course order
         */

        // 其实就是求topological sort的结果,如果不能,则返回空数组
        public int[] findOrder(int numCourses, int[][] prerequisites) {
            if (numCourses == 0) {
                return new int[]{};
            }
            Map<Integer, Set<Integer>> graph = initGraph(numCourses, prerequisites);
            // count indegree
            Map<Integer, Integer> count = new HashMap<>();
            for (int i = 0; i < numCourses; ++i) count.put(i, 0);
            for (int i = 0; i < numCourses; ++i) {
                for (int neighbor : graph.get(i)) {
                    count.put(neighbor, count.get(neighbor) + 1);
                }
            }
            // bfs
            List<Integer> res = new ArrayList<>();
            Deque<Integer> queue = new LinkedList<>();
            for (int node : count.keySet()) {
                if (count.get(node) == 0) {
                    res.add(node);
                    queue.addFirst(node);
                }
            }
            while (! queue.isEmpty()) {
                int node = queue.removeLast();
                for (int neighbor : graph.get(node)) {
                    count.put(neighbor, count.get(neighbor) - 1);
                    if (count.get(neighbor) == 0) {
                        res.add(neighbor);
                        queue.addFirst(neighbor);
                    }
                }
            }
            for (int node : count.keySet()) {
                if (count.get(node) > 0) return new int[]{};
            }
            int[] ret = new int[numCourses];
            for (int i = 0; i < ret.length; ++i) {
                ret[i] = res.get(ret.length - 1 - i);
            }
            return ret;
        }
        private Map<Integer, Set<Integer>> initGraph(int n, int[][] edges) {
            Map<Integer, Set<Integer>> graph = new HashMap<>();
            for (int i = 0; i < n; ++i) {
                graph.put(i, new HashSet<Integer>());
            }
            for (int[] edge : edges) {
                graph.get(edge[0]).add(edge[1]);
            }
            return graph;
        }
    }

Python Code:

update 2018-05-19 19:59:46

C++ Kahn's Algorithm BFS Solution

Java Naive DFS Solution

update 2018-06-19 22:40:53

Update: 精简版 C++ Count Indegree Solution

update 2018-10-10 22:24:21

Update: Java DFS Solution

之前的写法都是基于 count indegree 的,这种方法的确是一个更好的做法,也更容易实现,但之前上算法课的时候老师也讲过使用 DFS 来做 topological sort 的方法。

需要注意的有两点:

  • 要用 visitedfinished 两个set来分别探测是否有环以及当前node是否已经在别的支路中被搜索过,这里 finished 的作用其实就是看当前节点是否已经被加入 res 中;

  • 因为结果被存放在res中,可以利用dfs函数的返回值来标志是否有环。

Java Code: