60. Course Schedule II
Same setup as Course Schedule: [a, b] means take b before a. Return any valid order to take all courses, or an empty array if it is impossible.
Example 1
Input:
numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]Output:
[0,1,2,3]Explanation: Course 0 first, then 1 and 2 (any order), then 3.
[0,2,1,3] is also accepted.Example 2
Input:
numCourses = 2, prerequisites = [[0,1],[1,0]]Output:
[]Explanation: The two courses depend on each other.
Hint 1
The order in which Kahn’s algorithm removes nodes is a topological order.
Approach 1: Kahn’s algorithm
Record nodes as they reach in-degree 0.
⏱ Time O(V + E)💾 Space O(V + E)
Approach 2: DFS post-order ✅
Reverse post-order of a DFS, with cycle detection.
⏱ Time O(V + E)💾 Space O(V + E)
Reference solution for DFS post-order (time O(V + E), space O(V + E)). Each solution passes every test in all four languages.
class Solution:
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
adj = [[] for _ in range(numCourses)]
indeg = [0] * numCourses
for a, b in prerequisites:
adj[b].append(a)
indeg[a] += 1
q = deque(i for i in range(numCourses) if indeg[i] == 0)
order = []
while q:
u = q.popleft()
order.append(u)
for v in adj[u]:
indeg[v] -= 1
if indeg[v] == 0:
q.append(v)
return order if len(order) == numCourses else []class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
List<List<Integer>> adj = new ArrayList<>();
for (int i = 0; i < numCourses; i++) adj.add(new ArrayList<>());
int[] indeg = new int[numCourses], order = new int[numCourses];
for (int[] p : prerequisites) { adj.get(p[1]).add(p[0]); indeg[p[0]]++; }
ArrayDeque<Integer> q = new ArrayDeque<>();
for (int i = 0; i < numCourses; i++) if (indeg[i] == 0) q.add(i);
int k = 0;
while (!q.isEmpty()) {
int u = q.poll();
order[k++] = u;
for (int v : adj.get(u)) if (--indeg[v] == 0) q.add(v);
}
return k == numCourses ? order : new int[0];
}
}class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> adj(numCourses);
vector<int> indeg(numCourses, 0), order;
for (auto& p : prerequisites) { adj[p[1]].push_back(p[0]); indeg[p[0]]++; }
queue<int> q;
for (int i = 0; i < numCourses; i++) if (indeg[i] == 0) q.push(i);
while (!q.empty()) {
int u = q.front(); q.pop();
order.push_back(u);
for (int v : adj[u]) if (--indeg[v] == 0) q.push(v);
}
if ((int)order.size() != numCourses) return {};
return order;
}
};function findOrder(numCourses, prerequisites) {
const adj = Array.from({ length: numCourses }, () => []), indeg = new Array(numCourses).fill(0);
for (const [a, b] of prerequisites) { adj[b].push(a); indeg[a]++; }
const order = [];
for (let i = 0; i < numCourses; i++) if (indeg[i] === 0) order.push(i);
for (let h = 0; h < order.length; h++)
for (const v of adj[order[h]]) if (--indeg[v] === 0) order.push(v);
return order.length === numCourses ? order : [];
}Try solving it yourself first. Interviewers care more about how you explain the approach than about the finished code.
Watch the core idea of this problem step by step. Change the input and press Visualize.
Explained in the lesson Topological Sort, Dijkstra & Union-Find.
Run your code to see results here.