Course Schedule
Problem Statement
You’re a student planner with numCourses and prerequisites (pairs [a,b] meaning b before a). Can you finish all courses without a cycle? This medium-level graph problem is a dependency dance—use DFS or BFS to detect loops!
Example
Input: numCourses = 2, prerequisites = [[1,0]]
Output: true (0→1 is acyclic)
Input: numCourses = 2, prerequisites = [[1,0],[0,1]]
Output: false (Cycle: 0↔1)
Input: numCourses = 4, prerequisites = [[1,0],[2,1],[3,2]]
Output: true (0→1→2→3)
Code
Java
Python
JavaScript
class Solution { public boolean canFinish(int numCourses, int[][] prerequisites) { List> graph = new ArrayList<>(); for (int i = 0; i < numCourses; i++) graph.add(new ArrayList<>()); for (int[] pre : prerequisites) graph.get(pre[1]).add(pre[0]); int[] visited = new int[numCourses]; // 0=unvisited, 1=visiting, 2=visited for (int i = 0; i < numCourses; i++) { if (visited[i] == 0 && !dfs(graph, i, visited)) return false; } return true; } private boolean dfs(List
> graph, int node, int[] visited) { visited[node] = 1; for (int next : graph.get(node)) { if (visited[next] == 1) return false; // Cycle if (visited[next] == 0 && !dfs(graph, next, visited)) return false; } visited[node] = 2; return true; } }
from collections import defaultdict class Solution: def canFinish(self, numCourses, prerequisites): graph = defaultdict(list) for a, b in prerequisites: graph[b].append(a) visited = [0] * numCourses # 0=unvisited, 1=visiting, 2=visited def dfs(node): if visited[node] == 1: return False if visited[node] == 2: return True visited[node] = 1 for next_node in graph[node]: if not dfs(next_node): return False visited[node] = 2 return True for i in range(numCourses): if visited[i] == 0 and not dfs(i): return False return True
function canFinish(numCourses, prerequisites) { let graph = Array(numCourses).fill().map(() => []); for (let [a, b] of prerequisites) graph[b].push(a); let visited = new Array(numCourses).fill(0); // 0=unvisited, 1=visiting, 2=visited function dfs(node) { if (visited[node] === 1) return false; if (visited[node] === 2) return true; visited[node] = 1; for (let next of graph[node]) { if (!dfs(next)) return false; } visited[node] = 2; return true; } for (let i = 0; i < numCourses; i++) { if (visited[i] === 0 && !dfs(i)) return false; } return true; }
Explanation
- DFS Insight: Detect cycles in directed graph; cycle means impossible schedule.
- Flow: Build adjacency list, DFS with three states to catch back edges.
- Example Walkthrough: [[1,0],[0,1]] → 0→1→0 (cycle detected) → false.
- BFS Alt: Kahn’s algorithm with in-degree—remove nodes with no prereqs.
- Optimization: Early exit on cycle saves time.
Note
Time complexity: O(V + E), Space complexity: O(V + E). A scheduling saga—cycle-free and clever!