Topological Sort: Complete Interview Guide with DFS and Kahn's Algorithm
Master topological sort with interactive visualizations. Learn both DFS and Kahn's algorithm approaches, solve LeetCode problems, and ace your FAANG interviews.
Topological Sort: Complete Interview Guide
What is Topological Sort?
Topological Sort is an algorithm that produces a linear ordering of vertices in a Directed Acyclic Graph (DAG) such that for every directed edge , vertex comes before vertex in the ordering.
Why Interviewers Love It
- Fundamental graph algorithm used in scheduling, dependency resolution, and build systems
- Tests understanding of graph traversal (DFS/BFS)
- Appears in FAANG interviews in various forms (course schedule, task ordering, build dependencies)
- Combines multiple concepts: graphs, cycles detection, ordering
- Has two distinct approaches (DFS and Kahn’s algorithm)
When to Use Topological Sort
Use topological sort when you have:
- Dependency relationships between tasks or items
- Need to find a valid ordering that respects dependencies
- A directed acyclic graph (must verify no cycles)
- Problems involving prerequisites, course scheduling, or build order
Classic examples:
- Course prerequisites (take course A before course B)
- Package dependency management
- Task scheduling with constraints
- Compilation order of modules
Visual Intuition
Imagine you’re planning your morning routine:
- Can’t wear shoes before socks
- Can’t eat breakfast before preparing it
- Can’t leave home before getting dressed
These dependencies form a directed graph:
wake up
/ \
/ \
prepare get dressed
breakfast / \
\ socks shirt
\ \ /
\ shoes
\ /
leave home
Topological sort gives you a valid order: wake up → prepare breakfast → get dressed → socks → shirt → shoes → leave home
Key Properties
- Only works on DAGs (cycles make ordering impossible)
- Multiple valid orderings may exist
- Time complexity: where = vertices, = edges
- Two main approaches: DFS-based and BFS-based (Kahn’s algorithm)
Interactive Visualization: Kahn’s Algorithm
Kahn’s algorithm uses BFS and in-degree counting. It repeatedly finds nodes with no incoming edges (in-degree = 0) and processes them.
Kahn's Algorithm Topological Sort
In-Degree
Topological Order
Visited
How it works:
- Calculate in-degree (number of incoming edges) for each node
- Enqueue all nodes with in-degree 0
- While queue is not empty:
- Dequeue a node and add to result
- For each neighbor, reduce its in-degree by 1
- If neighbor’s in-degree becomes 0, enqueue it
- If result contains all nodes → success; otherwise → cycle detected
Interactive Visualization: DFS Approach
DFS-based approach explores as deep as possible, then adds nodes to result in reverse post-order.
DFS-based Topological Sort
Stack
Topological Order
Visited
How it works:
- Mark all nodes as unvisited
- For each unvisited node, run DFS
- After visiting all descendants of a node, push it to a stack
- Reverse the stack to get topological order
General Pattern: Identifying Topological Sort Problems
Problem Characteristics
✅ Use topological sort when you see:
- “Prerequisites” or “dependencies” mentioned
- “Order” or “sequence” needs to be determined
- Directed graph with constraints
- “Course schedule”, “task scheduling”, “build order”
- Need to detect if ordering is possible (cycle detection)
Solution Steps
- Build the graph from input (adjacency list)
- Choose algorithm: Kahn’s (easier to detect cycles) or DFS (more intuitive)
- Run the algorithm to get topological order
- Check validity: result should contain all nodes
- Return result based on problem requirements
Code Templates
Kahn’s Algorithm (BFS-based)
DFS-based Topological Sort
Three-Color DFS (Recommended)
The three-color marking method is a more elegant DFS implementation that uses a single state array instead of two boolean arrays. This approach is widely used in graph algorithms and is particularly well-suited for cycle detection.
Three Color States:
- White (0): Unvisited nodes
- Gray (1): Nodes currently being visited (in the current DFS path)
- Black (2): Nodes that have finished processing
Key Intuition:
- If you encounter a gray node during DFS → back edge found → cycle exists
- If you encounter a black node → node and its subtree fully processed → safe to skip
- If you encounter a white node → continue DFS exploration
Advantages:
- Cleaner code (only one state array needed)
- Easier to understand and explain
- Classic pattern in graph algorithms
- More intuitive cycle detection logic
Three-Color vs Two Boolean Arrays:
| Aspect | Three-Color Method | visited + inStack |
|---|---|---|
| Number of Arrays | 1 state array | 2 boolean arrays |
| Space Usage | Slightly less (single array) | Slightly more (two arrays) |
| Code Clarity | ⭐ More intuitive | Requires understanding two flags |
| Cycle Detection | Check for gray nodes | Check inStack |
| Industry Standard | ⭐ Classic graph algorithm pattern | Equally valid |
Recommendation: If you’re comfortable with the three-color method, use it in interviews—it demonstrates deeper knowledge. It’s the standard approach taught in graph algorithm textbooks.
LeetCode Problem Examples
Problem 1: Course Schedule II (LC 210)
Problem: There are numCourses courses labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you must take course bi first if you want to take course ai. Return the ordering of courses you should take to finish all courses. If impossible, return empty array.
Example:
Input: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
Output: [0,2,1,3] or [0,1,2,3]
Explanation:
Course 0 → Course 1 → Course 3
Course 0 → Course 2 ↗
Solution using Kahn’s Algorithm:
Complexity Analysis:
- Time: where = number of courses, = number of prerequisites
- Space: for the graph and auxiliary data structures
Key Insights:
- Graph direction:
prerequisites[i] = [a, b]meansb → a(take b before a) - Use in-degree to track how many prerequisites remain
- If final result has fewer courses than total, a cycle exists
Problem 2: Alien Dictionary (LC 269)
Note: This is a LeetCode Premium problem. You need a subscription to submit.
Problem: Given a sorted dictionary of an alien language, derive the order of characters in this language.
Example:
Input: words = ["wrt","wrf","er","ett","rftt"]
Output: "wertf"
Explanation:
From "wrt" and "wrf", we know 't' < 'f'
From "wrt" and "er", we know 'w' < 'e'
From "er" and "ett", we know 'r' < 't'
From "ett" and "rftt", we know 'e' < 'r'
So order is: w → e → r → t → f
Solution:
Complexity Analysis:
- Time: where = total length of all words
- Space: or for English alphabet
Key Insights:
- Compare only adjacent words in the sorted dictionary
- Only the first different character creates an ordering constraint
- Edge case: if
word1is a prefix ofword2but longer → invalid input - Multiple valid orderings possible; any valid one is acceptable
Problem 3: Minimum Height Trees (LC 310)
Problem: A tree is an undirected graph in which any two vertices are connected by exactly one path. Given such a tree with n nodes labeled from 0 to n - 1, find all root labels that result in minimum height trees.
Example:
Input: n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]]
Output: [3,4]
Tree structure:
0 1 2
\ | /
3
|
4
|
5
Solution (Topological Sorting from Leaves):
Complexity Analysis:
- Time: where = number of nodes
- Space: for the graph
Key Insights:
- This is a topological sorting variant on an undirected tree
- Trim leaves layer by layer until 1 or 2 nodes remain
- The remaining nodes are the centroids of the tree
- At most 2 nodes can be roots of minimum height trees
Edge Cases and Common Mistakes
Edge Cases to Handle
- Empty graph: No nodes → return empty result
- Single node: Only one node → return that node
- Cycle detection: If cycle exists → no valid topological sort
- Disconnected graph: Handle multiple components if required
- Self-loops: Usually invalid for topological sort
- Multiple edges: Between same pair of nodes
Common Mistakes
❌ Mistake 1: Forgetting to check for cycles
// Wrong: assumes graph is always acyclic
if (result.size() != numNodes) {
// Forgot to handle this case!
}
✅ Correct:
if (result.size() != numNodes) {
return new int[0]; // or throw exception
}
❌ Mistake 2: Wrong edge direction
// Wrong: reversed edge direction
graph[prerequisites[i][0]].add(prerequisites[i][1]);
✅ Correct: If [a, b] means “take b before a”:
graph[prerequisites[i][1]].add(prerequisites[i][0]);
❌ Mistake 3: Not handling multiple components
// Wrong: only starts DFS from node 0
dfs(0);
✅ Correct:
for (int i = 0; i < n; i++) {
if (!visited[i]) {
dfs(i);
}
}
❌ Mistake 4: Using visited alone for cycle detection in DFS
// Wrong: can't detect cycles properly
if (visited[neighbor]) return true; // This is wrong!
✅ Correct: Use both visited and inStack:
if (!visited[neighbor]) {
if (hasCycle(neighbor)) return true;
} else if (inStack[neighbor]) {
return true; // Back edge = cycle
}
Interview Tips
How to Explain Topological Sort
Framework for explanation:
- Define the problem: “Topological sort orders nodes in a DAG so dependencies come first”
- State assumptions: “The graph must be directed and acyclic”
- Choose approach: “I’ll use Kahn’s algorithm with in-degree counting” or “I’ll use DFS with post-order traversal”
- Explain cycle detection: “If we can’t process all nodes, a cycle exists”
- Analyze complexity: ” time, space”
When Interviewer Asks for Optimizations
Common follow-ups:
-
“Can you detect the cycle and return the cycle path?”
- Use DFS with recursion stack tracking
- When back edge found, reconstruct path from stack
-
“What if there are multiple valid orderings? Return all of them.”
- Use backtracking with DFS
- Explore all possible orderings (exponential time)
-
“What if the graph is very large and doesn’t fit in memory?”
- Use external sorting techniques
- Process graph in chunks
- Use disk-based graph databases
-
“Can you find the lexicographically smallest topological order?”
- Use priority queue (min-heap) instead of regular queue in Kahn’s algorithm
- Time becomes
Time & Space Complexity
Kahn’s Algorithm (BFS-based)
Time Complexity:
- Building graph:
- Calculating in-degrees:
- Processing each vertex once:
- Processing each edge once:
- Total:
Space Complexity:
- Adjacency list:
- In-degree array:
- Queue: worst case
- Result array:
- Total:
DFS-based Approach
Time Complexity:
- DFS visits each vertex once:
- DFS explores each edge once:
- Total:
Space Complexity:
- Adjacency list:
- Visited array:
- Recursion stack: in worst case
- Result stack:
- Total:
Best, Average, Worst Cases
Both algorithms have:
- Best case: - linear chain of dependencies
- Average case: - typical DAG structure
- Worst case: - fully connected DAG
Note: Time complexity is always regardless of graph structure, making topological sort very efficient!
When NOT to Use Topological Sort
❌ Don’t use topological sort when:
-
Graph has cycles
- Topological sort requires a DAG
- Use cycle detection algorithms instead
- Or find strongly connected components (Tarjan’s/Kosaraju’s algorithm)
-
Undirected graph
- Topological sort requires directed edges
- Consider: BFS, DFS, or spanning tree algorithms
-
Need shortest path
- Topological sort gives ordering, not distances
- Use: Dijkstra’s, Bellman-Ford, or A*
- Exception: Can use topological sort + DP for shortest path in DAG
-
Need all possible orderings
- Standard topological sort gives one ordering
- Use: Backtracking with DFS (exponential time)
-
Real-time updates to graph
- Topological sort is not incremental
- Consider: Dynamic topological ordering algorithms
Better Alternatives
| Your Need | Instead of Topo Sort | Use This |
|---|---|---|
| Find cycles | Topological sort | DFS with back edge detection |
| Shortest path | Topo sort + BFS | Dijkstra’s algorithm |
| All orderings | Single topo sort | Backtracking |
| Strongly connected components | Topo sort | Tarjan’s or Kosaraju’s |
| Undirected graph traversal | Topo sort | BFS or DFS |
Kahn’s vs DFS: Which to Choose?
| Aspect | Kahn’s Algorithm | DFS-based |
|---|---|---|
| Approach | BFS with in-degree | Post-order DFS |
| Intuition | Remove nodes with no dependencies | Finish children before parents |
| Cycle Detection | Easier (count processed nodes) | Requires extra inStack array |
| Space | + recursion stack | |
| Iterative vs Recursive | Iterative (queue) | Recursive (can be iterative) |
| Lexicographically smallest | Easy (use min-heap) | Harder |
| Interview preference | ⭐ More intuitive for beginners | ⭐ More elegant, less code |
Recommendation:
- Kahn’s algorithm if you need to detect cycles explicitly or want iterative solution
- DFS-based if you’re comfortable with recursion and want cleaner code
Summary: Key Takeaways for Interviews
Pattern Recognition
✅ Use topological sort when you see:
- Dependencies, prerequisites, or ordering constraints
- “Course schedule”, “task order”, “build dependencies”
- Need to detect if valid ordering exists (cycle detection)
- Directed acyclic graph (DAG) structure
Template to Memorize
Kahn’s Algorithm (4 steps):
- Build graph + calculate in-degrees
- Enqueue all nodes with in-degree 0
- While queue not empty: dequeue, add to result, reduce neighbors’ in-degrees
- Check if result.length == numNodes (cycle detection)
DFS Approach (4 steps):
- Build graph
- DFS from each unvisited node
- After visiting all descendants, push node to stack
- Reverse stack = topological order
Key Interview Points
- Always check for cycles - topological sort only works on DAGs
- Clarify edge direction -
[a, b]means what? (a → b or b → a?) - Handle multiple components - DFS from all unvisited nodes
- Time complexity: - very efficient!
- Space complexity: - need to store graph
Before You Leave the Interview
Make sure you’ve covered:
- ✅ Built the graph correctly (check edge direction!)
- ✅ Handled cycle detection
- ✅ Considered edge cases (empty graph, single node, disconnected components)
- ✅ Analyzed time and space complexity
- ✅ Tested with a small example
Final tip: Topological sort appears in 5-10% of FAANG graph interviews. Master both approaches (Kahn’s and DFS), and you’ll be ready for any variation!