name: Topological Sort slug: topological-sort difficulty_level: 3 pattern_type: algorithm display_order: 22 description: > Order vertices in a directed acyclic graph (DAG) such that for every edge u -> v, vertex u comes before v in the ordering. when_to_use: | - Course prerequisites / task dependencies - Build order / compilation order - Detecting cycles in directed graphs - Any problem with "do A before B" constraints metaphor: | Imagine getting dressed: you must put on underwear before pants, socks before shoes. Topological sort finds a valid order that respects all "must come before" rules. If there's a cycle (shirt requires jacket, jacket requires shirt), no valid order exists. core_concept: | Two main approaches: **Kahn's Algorithm (BFS):** Start with nodes having no incoming edges (in-degree 0). Process them, remove their edges, repeat. If all nodes processed, valid order exists. **DFS-based:** Do DFS, add nodes to result when backtracking (post-order). Reverse at end. Cycle exists if we revisit a node in current path. code_template: | from collections import deque def topological_sort_bfs(n: int, edges: list[tuple[int, int]]) -> list[int]: """Kahn's algorithm - returns empty list if cycle exists.""" # Build adjacency list and in-degree count graph = [[] for _ in range(n)] in_degree = [0] * n for u, v in edges: # u -> v (u must come before v) graph[u].append(v) in_degree[v] += 1 # Start with nodes having no prerequisites queue = deque([i for i in range(n) if in_degree[i] == 0]) result = [] while queue: node = queue.popleft() result.append(node) for neighbor in graph[node]: in_degree[neighbor] -= 1 if in_degree[neighbor] == 0: queue.append(neighbor) # If we processed all nodes, valid topological order exists return result if len(result) == n else [] recognition_signals: - "prerequisites" - "dependencies" - "ordering tasks" - "course schedule" - "build order" - "detect cycle in directed graph" - "do X before Y" common_mistakes: - title: Forgetting Cycle Detection description: | Assuming input is always a valid DAG. Must check if all nodes were processed (BFS) or if back-edge exists (DFS). fix: | BFS: Check `len(result) == n`. DFS: Track "visiting" state separately from "visited." - title: Wrong Edge Direction description: | Confusing "A depends on B" vs "A must come before B." These are opposite edge directions. fix: | Clarify: If A depends on B, edge is B -> A (B comes before A). variations: - name: Course Schedule (cycle detection) description: Return true/false if valid ordering exists example: "course-schedule" - name: Course Schedule II (find order) description: Return the actual ordering example: "course-schedule-ii" - name: Alien Dictionary description: Infer ordering from sorted alien words example: "alien-dictionary" related_patterns: - bfs - dfs prerequisite_patterns: - bfs - dfs