Topological Sort Pattern
📚 Topological Sort - Course Schedule
Dependencies: 0→1, 0→2, 1→3, 2→3
Queue (Courses with no prerequisites):
Course Order (Result):
Step 1: Start: Course 0 has no prerequisites (in-degree=0)
Progress: 1 / 5
Kahn's Algorithm:
- Find all nodes with in-degree 0 (no dependencies)
- Add them to queue and result
- Reduce in-degree of their neighbors
- Repeat until queue is empty
🎯 Explain Like I'm 5...
Imagine getting dressed 👕 in the morning! You MUST put on socks 🧦 BEFORE shoes 👟, and underwear BEFORE pants! Some things have rules!
👔 Getting Dressed Rules:
- • Socks 🧦 → THEN Shoes 👟 (can't wear shoes first!)
- • Underwear 🩲 → THEN Pants 👖
- • Shirt 👕 (no rules, wear anytime!)
✅ Good Orders (Topological Sort):
- • Socks → Underwear → Shirt → Pants → Shoes ✓
- • Underwear → Socks → Pants → Shoes → Shirt ✓
- • Shirt → Socks → Shoes → Underwear → Pants ❌ (Shoes before Socks - WRONG!)
🚀 The Trick: Do the things with NO requirements first! Then cross them off and see what's next. It's like a checklist where you can only do some things after finishing others! 📋✓
When Should You Use This Pattern?
- ✓Problems with dependencies or prerequisites
- ✓Finding valid ordering of tasks
- ✓Detecting cycles in directed graphs
- ✓Course scheduling, build systems
📝 Example 1: Course Schedule
Determine if you can finish all courses given prerequisites. (Cycle detection)
Step-by-Step Thinking:
- Build graph and count in-degrees (incoming edges)
- Add all courses with 0 in-degree to queue (no prerequisites)
- Process each course, reduce in-degree of dependents
- If all courses processed, possible! If not, there's a cycle.
import java.util.*;public class CourseSchedule { // Check if all courses can be finished public static boolean canFinish(int numCourses, int[][] prerequisites) { // Build graph and in-degree array Map<Integer, List<Integer>> graph = new HashMap<>(); int[] inDegree = new int[numCourses]; for (int i = 0; i < numCourses; i++) { graph.put(i, new ArrayList<>()); } for (int[] prereq : prerequisites) { int course = prereq[0]; int prerequisite = prereq[1]; graph.get(prerequisite).add(course); inDegree[course]++; } // Queue for courses with no prerequisites Queue<Integer> queue = new LinkedList<>(); for (int i = 0; i < numCourses; i++) { if (inDegree[i] == 0) { queue.offer(i); } } int coursesCompleted = 0; // Process courses while (!queue.isEmpty()) { int course = queue.poll(); coursesCompleted++; // Reduce in-degree of dependent courses for (int dependent : graph.get(course)) { inDegree[dependent]--; if (inDegree[dependent] == 0) { queue.offer(dependent); } } } return coursesCompleted == numCourses; } public static void main(String[] args) { int numCourses = 4; int[][] prerequisites = {{1, 0}, {2, 0}, {3, 1}, {3, 2}}; System.out.println("Can finish: " + canFinish(numCourses, prerequisites)); // Output: true // Valid order: 0 → 1 → 2 → 3 prerequisites = new int[][]{{1, 0}, {0, 1}}; System.out.println("Can finish (cycle): " + canFinish(2, prerequisites)); // Output: false (0 needs 1, 1 needs 0 - cycle!) }}📝 Example 2: Course Schedule II (Find Order)
Return the ordering of courses you should take to finish all courses.
import java.util.*;public class CourseScheduleII { public static int[] findOrder(int numCourses, int[][] prerequisites) { // Build graph and in-degree Map<Integer, List<Integer>> graph = new HashMap<>(); int[] inDegree = new int[numCourses]; for (int i = 0; i < numCourses; i++) { graph.put(i, new ArrayList<>()); } for (int[] prereq : prerequisites) { int course = prereq[0]; int prerequisite = prereq[1]; graph.get(prerequisite).add(course); inDegree[course]++; } // Queue for sources (in-degree 0) Queue<Integer> queue = new LinkedList<>(); for (int i = 0; i < numCourses; i++) { if (inDegree[i] == 0) { queue.offer(i); } } int[] order = new int[numCourses]; int index = 0; while (!queue.isEmpty()) { int course = queue.poll(); order[index++] = course; for (int dependent : graph.get(course)) { inDegree[dependent]--; if (inDegree[dependent] == 0) { queue.offer(dependent); } } } // If couldn't complete all courses, return empty return index == numCourses ? order : new int[0]; } public static void main(String[] args) { int numCourses = 4; int[][] prerequisites = {{1, 0}, {2, 0}, {3, 1}, {3, 2}}; int[] order = findOrder(numCourses, prerequisites); System.out.print("Course order: "); for (int course : order) { System.out.print(course + " "); } System.out.println(); // Output: 0 1 2 3 (or 0 2 1 3 - both valid) }}📝 Example 3: Alien Dictionary
Find the order of characters in an alien language given a sorted dictionary.
import java.util.*;public class AlienDictionary { public static String alienOrder(String[] words) { // Build graph Map<Character, Set<Character>> graph = new HashMap<>(); Map<Character, Integer> inDegree = new HashMap<>(); // Initialize graph for (String word : words) { for (char c : word.toCharArray()) { graph.putIfAbsent(c, new HashSet<>()); inDegree.putIfAbsent(c, 0); } } // Build edges by comparing adjacent words for (int i = 0; i < words.length - 1; i++) { String word1 = words[i]; String word2 = words[i + 1]; int minLen = Math.min(word1.length(), word2.length()); // Find first different character for (int j = 0; j < minLen; j++) { char c1 = word1.charAt(j); char c2 = word2.charAt(j); if (c1 != c2) { // c1 comes before c2 if (!graph.get(c1).contains(c2)) { graph.get(c1).add(c2); inDegree.put(c2, inDegree.get(c2) + 1); } break; } } // Invalid case: word1 is prefix but comes after if (word1.length() > word2.length() && word1.startsWith(word2)) { return ""; } } // Topological sort Queue<Character> queue = new LinkedList<>(); for (char c : inDegree.keySet()) { if (inDegree.get(c) == 0) { queue.offer(c); } } StringBuilder result = new StringBuilder(); while (!queue.isEmpty()) { char c = queue.poll(); result.append(c); for (char next : graph.get(c)) { inDegree.put(next, inDegree.get(next) - 1); if (inDegree.get(next) == 0) { queue.offer(next); } } } return result.length() == inDegree.size() ? result.toString() : ""; } public static void main(String[] args) { String[] words = {"wrt", "wrf", "er", "ett", "rftt"}; System.out.println("Alien order: " + alienOrder(words)); // Output: "wertf" // From comparisons: w<e, t<f, r<t }}🔑 Key Points to Remember
- 1️⃣Uses in-degree (Kahn's algorithm) or DFS
- 2️⃣If can't process all nodes → cycle exists
- 3️⃣Time Complexity: O(V + E) where V=vertices, E=edges
- 4️⃣Only works on Directed Acyclic Graphs (DAG)
💪 Practice Problems
- • Tasks Scheduling
- • All Tasks Scheduling Orders
- • Minimum Height Trees
- • Sequence Reconstruction