Problem Statement

Course Schedule II

You have numCourses courses to take, numbered from 0. Some courses can only be taken after you finish other courses first. Those rules come in the array prerequisites. Each pair [a, b] means "to take course a, you must finish course b first." Your job is to return one valid order in which to take all the courses. If more than one order works, any of them is fine. If it is impossible to finish them all, return an empty array.

hardGraphsGraphsTime: O(V + E) · Space: O(V + E)

Signals to notice

find a valid ordering of all coursesreturn the actual ordertopological sort

Brute force first

Try all permutations and check validity. Brute-force permutation with constraint checking. That instinct is useful because it follows the prompt literally, but it usually keeps revisiting work the problem is begging you to organize.

The key insight

Topological sort with BFS (Kahn's): start with courses having no prerequisites (in-degree 0), process them, reduce neighbors' in-degrees. If all courses are processed, the order is valid. Instead of recomputing the world every time, you preserve just enough context to let the next decision become obvious.

Trace it on numCourses=4, prerequisites=[[1,0],[2,0],[3,1],[3,2]]

Build adj (edge a->prereq b): adj[0]=[], adj[1]=[0], adj[2]=[0], adj[3]=[1,2]; state=[0,0,0,0]; result=[]
i=0 dfs(0): no neighbors -> state[0]=2 (done); result=[0]
i=1 dfs(1): nei 0 done -> state[1]=2; result=[0,1]
i=2 dfs(2): nei 0 done -> state[2]=2; result=[0,2... wait, appended after both done] result=[0,1,2]
i=3 dfs(3): nei 1 done, nei 2 done -> state[3]=2; result=[0,1,2,3]
All dfs returned true (no cycle). Because adj edges point course->prerequisite, post-order already lists prerequisites before dependents, so DO NOT reverse.
Return [0,1,2,3] (valid: every prerequisite precedes its course; matches a valid topological order like the example's [0,2,1,3])

What must stay true

A course can be taken only when all its prerequisites are done. In-degree 0 means all prerequisites are satisfied. Processing these first and updating neighbors' in-degrees simulates the natural ordering. As long as that statement keeps holding, you can trust the steps built on top of it.

Shape of the loop

build adj where adj[a] holds prerequisites b of course a (edge a->b)
state[*] = UNVISITED; result = []
dfs(node): if VISITING return false (cycle); if DONE return true
  mark VISITING; for nei in adj[node]: if !dfs(nei) return false
  mark DONE; result.append(node); return true   // appends prereqs before dependents
for each course i: if !dfs(i) return []
return result   // already prereq-first; do NOT reverse

Pseudocode only — the full worked solution lives in the Solution tab.

Easy way to go wrong

Not detecting cycles — if the result has fewer courses than total, there's a circular dependency. Return an empty array, not a partial result. The fix is usually to return to the meaning of each move, not just the steps themselves.

Graphs Pattern