Description
There are a total of numCourses
courses you have to take, labeled from 0
to numCourses - 1
. You are given an array prerequisites
where prerequisites[i] = [ai, bi]
indicates that you must take course bi
first if you want to take course ai
.
- For example, the pair
[0, 1]
, indicates that to take course0
you have to first take course1
.
Return the ordering of courses you should take to finish all courses. If there are many valid answers, return any of them. If it is impossible to finish all courses, return an empty array.
Example 1:
Input: numCourses = 2, prerequisites = [[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: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
Output: [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].
Example 3:
Input: numCourses = 1, prerequisites = []
Output: [0]
Constraints:
1 <= numCourses <= 2000
0 <= prerequisites.length <= numCourses * (numCourses - 1)
prerequisites[i].length == 2
0 <= ai, bi < numCourses
ai != bi
- All the pairs
[ai, bi]
are distinct.
Solutions
Solution 1
Intuition
DFS
Code
class Solution {
private static final int WHITE = 1;
private static final int GRAY = 2;
private static final int BLACK = 3;
boolean isPossible;
Map<Integer, Integer> color;
Map<Integer, List<Integer>> adjList;
List<Integer> topologicalOrder;
private void init(int numCourses) {
isPossible = true;
color = new HashMap<>(numCourses);
adjList = new HashMap<>(numCourses);
topologicalOrder = new ArrayList<>();
// By default, all vertices are WHITE
for (int i = 0; i < numCourses; i++) {
color.put(i, WHITE);
}
}
private void dfs(int node) {
// Don't recurse further if we found a cycle already
if (!isPossible) {
return;
}
// Start the recursion
color.put(node, GRAY);
// Traverse on neighboring vertices
for (Integer neighbor : adjList.getOrDefault(node, new ArrayList<>())) {
if (color.get(neighbor) == WHITE) {
dfs(neighbor);
} else if (color.get(neighbor) == GRAY) {
// An edge to a GRAY vertex represents a cycle
isPossible = false;
}
}
// Recursion ends. We mark it as black
color.put(node, BLACK);
topologicalOrder.add(node);
}
public int[] findOrder(int numCourses, int[][] prerequisites) {
init(numCourses);
// Create the adjacency list representation of the graph
for (int[] prerequisite : prerequisites) {
int dest = prerequisite[0];
int src = prerequisite[1];
List<Integer> lst = adjList.getOrDefault(src, new ArrayList<>());
lst.add(dest);
adjList.put(src, lst);
}
// If the node is unprocessed, then call dfs on it.
for (int i = 0; i < numCourses; i++) {
if (color.get(i) == WHITE) {
dfs(i);
}
}
int[] order;
if (isPossible) {
order = new int[numCourses];
for (int i = 0; i < numCourses; i++) {
order[i] = topologicalOrder.get(numCourses - i - 1);
}
} else {
order = new int[0];
}
return order;
}
}
Complexity
- Time: O(V+E)
- Space: O(V+E)
Solution 2
Intuition
BFS
Code
class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
Map<Integer, List<Integer>> adjList = new HashMap<>();
int[] indegree = new int[numCourses];
int[] topologicalOrder = new int[numCourses];
// Create the adjacency list representation of the graph
for (int[] prerequisite : prerequisites) {
int dest = prerequisite[0];
int src = prerequisite[1];
List<Integer> lst = adjList.getOrDefault(src, new ArrayList<Integer>());
lst.add(dest);
adjList.put(src, lst);
// Record in-degree of each vertex
indegree[dest] += 1;
}
// Add all vertices with 0 in-degree to the queue
Queue<Integer> q = new LinkedList<Integer>();
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0) {
q.add(i);
}
}
int index = 0;
// Process until the Q becomes empty
while (!q.isEmpty()) {
int node = q.remove();
topologicalOrder[index++] = node;
// Reduce the in-degree of each neighbor by 1
if (adjList.containsKey(node)) {
for (Integer neighbor : adjList.get(node)) {
indegree[neighbor]--;
// If in-degree of a neighbor becomes 0, add it to the Q
if (indegree[neighbor] == 0) {
q.add(neighbor);
}
}
}
}
// Check to see if topological sort is possible or not.
if (index == numCourses) {
return topologicalOrder;
}
return new int[0];
}
}
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> g(numCourses);
vector<int> in(numCourses, 0);
for (auto& p : prerequisites) {
int a = p[0], b = p[1];
// b -> a
g[b].push_back(a);
// how many prerequisites need to learn a course?
in[a] ++;
}
queue<int> q;
// in = 0, means you've already finished the prerequisites, and you can learn this course
for (int i = 0; i < numCourses; i++)
if (in[i] == 0) q.push(i);
vector<int> res;
while (!q.empty()) {
int p = q.front();
q.pop();
res.push_back(p);
for (auto& c : g[p]) {
if (--in[c] == 0) q.push(c);
}
}
if (res.size() == numCourses) return res;
else return {};
}
};
Complexity
- Time: O(V+E)
- Space: O(V+E)
Top comments (0)