【LeetCode 210】Course Schedule 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.

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] .

Example 2:

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] .

Note:

  1. The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a >graph is represented.
  2. You may assume that there are no duplicate edges in the input prerequisites.

思路

根据Example 1,可以画出如下所示的有向图,这个有向图可以包含例子中所给出的所有信息,并且根据这个有向图可以很快地得到答案。
pic_example_1
所以这一题的思路就是将所给地课程信息用有向图地形式来表示,并且根据一定的顺序对途中的节点进行排列,最后将此顺序以数组的形式输出。

这种一定的顺序必须要满足如下要求:如果在有向图G中,有某一条边由A节点指向B节点,那么在此种一定的顺序中,A节点必须出现在B节点的前面。例如在上图中,0 \rightarrow 1 \rightarrow 2 \rightarrow 3就符合这种一定的顺序,0 \rightarrow 1 \rightarrow 3 \rightarrow 2就不符合这种一定的顺序

在图论中,这种一定的顺序被称为 Topological Sort,(参考 topological sort ),为了获得Topological Sort,我们需要用到一个Set和一个Stack,采用DFS的遍历方法,Set中存放已经或者正在访问的节点,每当有节点结束访问(当这个节点的所有子节点都被访问完毕时,这个节点就结束了被访问)时,就将结束访问的节点弹入栈,最终将Stack中的节点依此弹出,就得到了Topological Sort。

但是上述方法有一个限制,那就是有向图没有闭环。因为当有向图存在闭环时,这个有向图无法得到Topological Sort。那么这题的思路就是:首先将所给数据用有向图的方式表示,接着对这个有向图进行DFS来得到Topological Sort,一旦发现闭环的话立马输出空数组表示无法完成所有的课程。

问题1: 如何表示有向图?
遍历题目中所给的表示课程之间依赖关系的数组,用邻接表表示即可。

问题2: 如何发现闭环?
在Set中的节点其实有两种状态:正在进行访问(子节点没有访问完毕)和结束访问(所有的子节点都结束访问),如果在DFS的过程中遇到了正在访问的节点,说明肯定遇到了闭环。我们可以用0,1, 2来标记每个节点现在的访问状态,0表示尚未访问,1表示正在访问,2表示已经结束访问。这样在DFS的过程中可以发现闭环。

代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class Solution {
    private boolean dfs(int i, List<Integer>[] adj, List<Integer> s, int[] visited) {
        if (visited[i] == 0) {
            visited[i] = 1;
            for (int v : adj[i]) {
                if (dfs(v, adj, s, visited)) return true;
            }
            visited[i] = 2;
            s.add(i);
        }
        else if (visited[i] == 1) return true;
        return false;
    }

    public int[] findOrder(int numCourses, int[][] prerequisites) {
        List<Integer>[] adj = new ArrayList[numCourses];
        for (int i=0; i<numCourses; ++i)
            adj[i] = new ArrayList<Integer>();
        for (int[] courses : prerequisites)
            adj[courses[1]].add(courses[0]);

        List<Integer> s = new ArrayList();
        int[] visited = new int[numCourses];
        for(int i=0; i<numCourses; ++i) {
            if (dfs(i, adj, s, visited)) return new int[0];
        }
        Collections.reverse(s);
        int[] result = s.stream().mapToInt(Integer::intValue).toArray();
        return result;
    }
}

参考Knowledge Center的解答(视频)

猜你喜欢

转载自blog.csdn.net/qq_27637285/article/details/107464731