Skip to content

Topological Sort Patterns: Mental Models & Intuition

Build deep understanding of when and why Topological Sort works.

The Core Insight

Topological Sort orders nodes so all dependencies come first.

For a directed graph where edge A β†’ B means "A must come before B": - Find an ordering where every edge points forward - If no such ordering exists, there's a cycle - A DAG (Directed Acyclic Graph) always has at least one valid ordering


Mental Model 1: The Dependency Chain

Prerequisites:         Valid Order:
  0 β†’ 1                [0, 2, 1, 3]
  0 β†’ 2                or [0, 1, 2, 3]
  1 β†’ 3                or [0, 2, 1, 3]
  2 β†’ 3

Think of it as: "What can I do with no blockers?"

Key insight: At any point, nodes with no remaining dependencies can be processed.


Mental Model 2: Kahn's Algorithm (Peeling Layers)

Imagine removing nodes layer by layer:

Initial:           Layer 1:          Layer 2:          Layer 3:
  0 β†’ 1 β†’ 3        Remove 0          Remove 1, 2       Remove 3
  ↓                (in-degree 0)     (in-degree 0)     (in-degree 0)
  2 ───↗

In-degrees:        After removing 0:  After removing 1,2:
  0: 0 ←start      1: 0 ←start        3: 0 ←start
  1: 1             2: 0 ←start
  2: 1             3: 2
  3: 2

Order: [0, 1, 2, 3] or [0, 2, 1, 3]

Key operations: - Track in-degree for each node - Process nodes with in-degree 0 - Decrement neighbors' in-degrees


Mental Model 3: DFS Postorder (Finish Last)

DFS explores deeply, adds nodes when "done" with them:

Start from 0:
  Visit 0
    Visit 1
      Visit 3 (no more neighbors)
        Done with 3, add to result: [3]
      Done with 1, add to result: [3, 1]
    Visit 2
      3 already done
      Done with 2, add to result: [3, 1, 2]
    Done with 0, add to result: [3, 1, 2, 0]

Reverse: [0, 2, 1, 3] ← Valid topological order!

Why reverse? We add nodes after processing all descendants, so they end up last. Reversing puts them first.


Mental Model 4: Three-Color Cycle Detection

Colors:
  WHITE = unvisited
  GRAY  = currently in recursion stack (being explored)
  BLACK = fully processed (safe)

Cycle Detection:
  If we visit a GRAY node β†’ We found a back edge β†’ CYCLE!

  0 (GRAY) β†’ 1 (GRAY) β†’ 2 (GRAY) β†’ 0 (GRAY!) ← CYCLE!

Key insight: A back edge (edge to ancestor in DFS tree) means a cycle.


Mental Model 5: Safe States (Reverse Thinking)

For "eventual safe states" problems:

Original Graph:        Reverse Perspective:
  A β†’ B β†’ C (terminal)    Start from terminals
  A β†’ D β†’ E β†’ A (cycle)   Propagate "safety" backwards

Safe: C, B, then A      Unsafe: E, D, anything reaching them
(if A only went to B)

Key insight: A node is safe iff ALL paths lead to terminals.


Pattern Recognition Checklist

Signal Words Pattern Key Insight
"prerequisites", "dependencies" Topological Sort Order respecting edges
"can all be completed?" Cycle Detection len(result) == n
"valid ordering" Return Order Collect during traversal
"safe states" Reverse Analysis DFS three-color or reverse graph
"multi-level ordering" Nested Topo Sort Sort groups, then items

When to Use Kahn's vs DFS

Use Kahn's (BFS) Use DFS Postorder
Need to process in levels/batches Simpler implementation
Parallelization needed Already doing DFS
Dynamic graph updates Finding all orderings
Streaming/online processing Stack depth not an issue

Common Pitfalls

Pitfall 1: Wrong Edge Direction

# WRONG: "A depends on B" doesn't mean A β†’ B
# If A depends on B, B must come BEFORE A
# So the edge is B β†’ A (or track in-degree[A]++)

# Course [1, 0] means "1 depends on 0" β†’ edge: 0 β†’ 1
graph[0].append(1)
in_degree[1] += 1

Pitfall 2: Forgetting Disconnected Components

# WRONG: Only start from one node
dfs(0)

# CORRECT: Start from ALL unvisited nodes
for node in range(n):
    if color[node] == WHITE:
        dfs(node)

Pitfall 3: Self-Loops

# A node depending on itself is a cycle!
if course == prereq:
    return False  # Impossible

Pitfall 4: Forgetting to Reverse in DFS

# DFS postorder gives reverse topological order
result.append(node)  # Add when done
...
return result[::-1]  # Don't forget to reverse!

Practice Progression

Level 1: Core Concept

  1. LC 207 - Course Schedule (Detect if order exists)

Level 2: Return Order

  1. LC 210 - Course Schedule II (Return actual order)

Level 3: Safe States

  1. LC 802 - Find Eventual Safe States (Not in any cycle)

Level 4: Advanced

  1. LC 1203 - Sort Items by Groups (Two-level topo sort)

Quick Reference Card

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 TOPOLOGICAL SORT                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                          β”‚
β”‚  KAHN'S (BFS):                DFS POSTORDER:            β”‚
β”‚  ─────────────                ──────────────            β”‚
β”‚  in_degree[v]++               WHITE β†’ GRAY β†’ BLACK      β”‚
β”‚  queue: in_degree 0           Add node when BLACK       β”‚
β”‚  process, decrement           Reverse at end            β”‚
β”‚                                                          β”‚
β”‚  CYCLE DETECTION:                                        β”‚
β”‚  ─────────────────                                       β”‚
β”‚  Kahn's: len(result) < n                                β”‚
β”‚  DFS: GRAY β†’ GRAY (back edge)                           β”‚
β”‚                                                          β”‚
β”‚  PATTERNS:                                               β”‚
β”‚  ─────────                                               β”‚
β”‚  Ordering:    Return result list                        β”‚
β”‚  Can finish:  len(result) == n                          β”‚
β”‚  Safe nodes:  Not reachable from any cycle              β”‚
β”‚  Two-level:   Sort groups, then items within groups     β”‚
β”‚                                                          β”‚
β”‚  COMPLEXITY:                                             β”‚
β”‚  ─────────                                               β”‚
β”‚  Time:  O(V + E)                                         β”‚
β”‚  Space: O(V + E) for graph + O(V) for state             β”‚
β”‚                                                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜