summary:
directed graph | dfs | topological sort
package myapp.kit.leetcode.graph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* 210
* medium
* https://leetcode.com/problems/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:
*
* The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
* You may assume that there are no duplicate edges in the input prerequisites.
*
* Created with IDEA
* author:Dingsheng Huang
* Date:2020/4/16
* Time:下午1:58
*/
public class CourseScheduleII {
private static Integer NODE_COLOR_WHITE = 0;
private static Integer NODE_COLOR_GRAY = 1;
private static Integer NODE_COLOR_BLACK = 2;
private Map<Integer, List<Integer>> graph = new HashMap<>();
private Map<Integer, Integer> color = new HashMap<>();
private List<Integer> topologicalOrder = new ArrayList<>();
private boolean cycle = false;
private void dfs(Integer node) {
if (cycle) {
return;
}
color.put(node, NODE_COLOR_GRAY);
for (Integer nextNode : graph.getOrDefault(node, new ArrayList<>())) {
if (color.get(nextNode) == NODE_COLOR_WHITE) {
dfs(nextNode);
} else if (color.get(nextNode) == NODE_COLOR_GRAY) {
cycle = true;
} else {
// black
continue;
}
}
color.put(node, NODE_COLOR_BLACK);
topologicalOrder.add(node);
}
public int[] findOrder(int numCourses, int[][] prerequisites) {
// color init
for (int i = 0; i < numCourses; i++) {
color.put(i, NODE_COLOR_WHITE);
}
// graph init
for (int[] pair : prerequisites) {
List<Integer> neighbors = graph.getOrDefault(pair[1], new ArrayList<>());
neighbors.add(pair[0]);
graph.put(pair[1], neighbors);
}
for (int i = 0; i < numCourses; i++) {
if (color.get(i) == NODE_COLOR_WHITE) {
dfs(i);
// pruning
if (cycle) {
return new int[0];
}
}
}
if (cycle) {
return new int[0];
}
int[] answer = new int[numCourses];
for (int i = topologicalOrder.size() - 1; i >= 0; i--) {
answer[numCourses - i - 1] = topologicalOrder.get(i);
}
return answer;
}
}