Course Schedule II is the classic topological sort problem. You are given courses with prerequisites and asked for an order in which you can actually take them — or proof that no such order exists because the prerequisites form a cycle.
Problem. There are numCourses courses labeled 0 to numCourses - 1. Each pair
[a, b] in prerequisites means you must take course b before course a. Return any
ordering of courses you can follow to finish them all. If it is impossible, return [].
Example: numCourses = 4, prerequisites = [[2, 0], [2, 1], [3, 2]] → answer [0, 1, 2, 3]
(take 0 and 1 first, then 2, then 3).
The slow way first
You could try every permutation of courses and check each one against all the prerequisites. With n courses that is n! orderings — hopelessly slow for anything beyond a handful of courses.
The better question: which course can I take right now? A course is takeable the moment it has no unmet prerequisites. If we keep taking those and removing them, the courses they unlocked become takeable next. That is exactly Kahn algorithm.
The idea: take whatever has no prerequisites left
Model the courses as a directed graph: an arrow u → v means u before v. For each course, count its in-degree — the number of incoming arrows, i.e. how many prerequisites it still has. Repeatedly take a course with in-degree 0, append it to the answer, and decrement the in-degree of everything it points to. A neighbor that drops to 0 is now takeable, so queue it.
If we manage to take every course, the order is valid. If some courses stay stuck above 0, they sit in a cycle of prerequisites that can never be satisfied, so we return [].
Walk through it
Step through the animation. We start by counting in-degrees: courses 0 and 1 need nothing (in: 0), course 2 needs both of them (in: 2), course 3 needs 2 (in: 1). Courses 0 and 1 go into the queue. As each is taken, we relax the arrows out of it — 2 drops from 2 to 1 to 0, then 3 drops to 0. The order fills up to [0, 1, 2, 3].
Pseudocode
build graph and an in-degree count for every course
queue = every course whose in-degree is 0
order = []
while the queue is not empty:
node = remove a course from the queue
append node to order
for each neighbor of node:
decrement neighbor's in-degree
if it just hit 0:
add neighbor to the queue
if order contains every course:
return order # valid topological order
return [] # a cycle blocked some courseThe Python solution
def find_order(numCourses, prerequisites):
graph = [[] for _ in range(numCourses)]
indeg = [0] * numCourses
for dest, src in prerequisites:
graph[src].append(dest)
indeg[dest] += 1
queue = [c for c in range(numCourses) if indeg[c] == 0]
order = []
while queue:
node = queue.pop(0)
order.append(node)
for nxt in graph[node]:
indeg[nxt] -= 1
if indeg[nxt] == 0:
queue.append(nxt)
if len(order) == numCourses:
return order
return []graph[src]lists the courses unlocked bysrc;indeg[dest]counts how many prerequisitesdeststill has.- The first
queueholds every course with zero prerequisites — the only ones takeable at the start. - Each loop pops a takeable course, appends it to
order, and relaxes its edges by decrementing each neighbor. - A neighbor that hits
0has all its prerequisites done, so it joins the queue. - At the end, if
orderis missing courses, a cycle blocked them and we return[].
Complexity
| Case | Time | Notes |
|---|---|---|
| Try every permutation | O(n!) (slow) | brute force ordering |
| Kahn topological sort | O(V + E) (moderate) | each course and edge handled once |
O(V + E) (moderate)We visit each course once and walk each prerequisite edge once, so the work is linear in the number of courses plus prerequisites. The extra space is the graph, the in-degree array, and the queue.
When this pattern shows up
Whenever a problem asks for an order that respects dependencies — build steps, task scheduling, compile order, "can you finish all of these" — think topological sort. Kahn algorithm (in-degree + queue) is the iterative version; a DFS post-order is the recursive alternative.
Mind the edge direction. The pair [a, b] means b comes before a, so the arrow is b → a and it is
a in-degree that goes up. Flip it and your whole order comes out reversed.
Practice
After taking courses 0 and 1, what is course 2 in-degree, and what happens to it?
1. What does a course in-degree represent?
2. Which courses go into the queue at the very start?
3. How does Kahn algorithm detect that no valid order exists?
4. What is the time complexity of this approach?