Pattern #20
Topological Sort
AdvancedOrder nodes so every directed edge goes from earlier to later.
When to use
Prerequisites, build order, or any DAG dependency constraints.
Recognition cues
- Course schedule / order
- Alien dictionary
- Indegree queue (Kahn) or DFS postorder
Common pitfalls
- Not detecting cycles (incomplete order)
- Building the graph in the wrong direction
- Multiple valid orders: any is fine unless specified
90-second recognition drill
Which pattern fits best?
- Course schedule / order
- Alien dictionary
- Indegree queue (Kahn) or DFS postorder
Interactive
Mental model
A full worked walkthrough of the invariant. Pause, scrub the dots, or use ← →. Aim to narrate each step yourself.
Step 1 of 8
A
B
C
D
indegree A0 B1 C1 D2
Prereq graph: A before B and C; B and C before D.
How to think about it
In a DAG, nodes with indegree 0 can come first. Kahn’s algorithm: queue them, emit, reduce neighbors’ indegrees. If you emit fewer than n nodes, a cycle exists. DFS variant: add node to front after exploring children.
Template shapes
| Shape | Core move | Notes |
|---|---|---|
| Kahn BFS | Indegree + queue | Detect cycle by count |
| DFS | Recursion stack colors | Postorder prepend |
| Lex smallest | Min-heap instead of queue | Deterministic order |
Complexity baseline
O(V+E) time and space.
From template to problem
- Build adjacency list and indegree array.
- Enqueue all indegree 0.
- Pop, append to order, decrement neighbors; enqueue if 0.
- If order.length < n → cycle / impossible.
Template
Same skeleton in TypeScript, Python, and C#. Adapt the invariant; keep the structure.
Topological Sort · Template
/** Topo template: Kahn BFS; empty array if cycle. */
export function topoSort(n: number, edges: number[][]): number[] {
const g: number[][] = Array.from({ length: n }, () => []);
const indeg = new Array(n).fill(0);
for (const [u, v] of edges) {
g[u!]!.push(v!);
indeg[v!]++;
}
const q: number[] = [];
for (let i = 0; i < n; i++) if (indeg[i] === 0) q.push(i);
const order: number[] = [];
while (q.length) {
const u = q.shift()!;
order.push(u);
for (const v of g[u]!) if (--indeg[v]! === 0) q.push(v);
}
return order.length === n ? order : [];
}
/** Topo template: Kahn BFS; empty array if cycle. */
export function topoSort(n: number, edges: number[][]): number[] {
const g: number[][] = Array.from({ length: n }, () => []);
const indeg = new Array(n).fill(0);
for (const [u, v] of edges) {
g[u!]!.push(v!);
indeg[v!]++;
}
const q: number[] = [];
for (let i = 0; i < n; i++) if (indeg[i] === 0) q.push(i);
const order: number[] = [];
while (q.length) {
const u = q.shift()!;
order.push(u);
for (const v of g[u]!) if (--indeg[v]! === 0) q.push(v);
}
return order.length === n ? order : [];
}
#StatusProblemTypeDifficultyDone
- 1#207 Course ScheduleGuidemedium
- 2#210 Course Schedule IIGuidemedium
- 3#269 Alien DictionaryGuidehard
- 4#310 Minimum Height TreesGuidemedium
- 5#1136 Parallel CoursesGuidemedium
- 6#1203 Sort Items by Groups Respecting DependenciesGuidehard