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();
}