Leetcode 207. Course Schedule
Given courses as nodes and prerequisite pairs as directed edges, determine whether the directed graph is acyclic ā return true if a topological ordering exists (all courses can be completed), otherwise false if a cycle prevents completion.
DESCRIPTION
Given courses as nodes and prerequisite pairs as directed edges, determine whether the directed graph is acyclic ā return true if a topological ordering exists (all courses can be completed), otherwise false if a cycle prevents completion.
Input:
numCourses = 2, prerequisites = [[1,0]]
Output:
true
Explanation: There are 2 courses. To take course 1, you must first take course 0. The ordering [0,1] satisfies all prerequisites.
Constraints:
- 1 <= numCourses <= 2000
- 0 <= prerequisites.length <= 5000
- prerequisites[i].length == 2
- 0 <= ai, bi < numCourses
- All prerequisite pairs are unique
- The graph may contain multiple edges and self-loops
Understanding the Problem
Let's understand what we're being asked to do. We have courses represented as nodes and prerequisite relationships as directed edges. For example, if course 1 requires course 0 as a prerequisite, we have an edge from 0 to 1.
Given numCourses = 2 and prerequisites = [[1,0]], this means course 1 depends on course 0. We can complete course 0 first, then course 1, so return true.
But consider numCourses = 2 and prerequisites = [[1,0],[0,1]]. Course 1 requires course 0, AND course 0 requires course 1. This creates a circular dependency - we can't complete either course! Return false.
Key constraint: We need to determine if a valid ordering exists where all prerequisites are satisfied before taking a course.
Edge cases to consider: What if there are no prerequisites at all? (all courses can be completed). What if a course has no prerequisites but other courses depend on it? What if there are multiple disconnected components in the graph?
Brute Force Approach
Use depth-first search with cycle detection. For each course, recursively visit all its prerequisites, marking nodes as 'visiting' during traversal and 'visited' after completion. If we encounter a node marked 'visiting' during recursion, we've found a cycle. This approach explores all paths but may revisit nodes multiple times, making it less efficient than the optimal solution.
Test Your Knowledge
Login to take the complexity quiz and track your progress
Complexity Analysis
Time Complexity: O(V + E) We visit each course (vertex) once and traverse each prerequisite edge once during DFS traversal
Space Complexity: O(V + E) We need space for the adjacency list representation O(V + E), recursion stack O(V), and visited state tracking O(V)
Building Intuition
A course can only be completed if all its prerequisites are completed first. This means we need to process courses in an order where dependencies come before dependents.
The critical insight: if there's a cycle in the dependency graph (course A requires B, B requires C, C requires A), then no valid ordering exists because we'd need to complete A before starting A!
This transforms the problem from 'can we complete all courses?' to 'does the directed graph have a cycle?'
If the graph is acyclic (no cycles), we can find a topological ordering - a linear arrangement where all edges point forward. If there's a cycle, no such ordering exists.
Think about getting dressed in the morning. You must put on socks before shoes, underwear before pants. These are dependencies that form a directed graph.
If the rules were: 'put on shoes before socks' AND 'put on socks before shoes', you'd have a circular dependency - impossible to satisfy! But if the dependencies form a tree-like structure with no cycles, you can find a valid order to get dressed.
Common Mistakes
Confusing directed and undirected graphs - prerequisites create directed edges, not bidirectional relationships
Not handling disconnected components - some courses may have no prerequisites or dependents, forming separate subgraphs
In DFS approach, forgetting to mark nodes as 'visiting' during recursion leads to incorrect cycle detection
In BFS approach, not properly updating in-degrees when processing nodes can cause incorrect results
Assuming that if we can't complete all courses, we can't complete any - partial completion is possible when cycles exist in only part of the graph
Optimal Solution
Use Kahn's algorithm for topological sorting with BFS. First, calculate the in-degree (number of prerequisites) for each course. Start with courses that have zero in-degree (no prerequisites) and add them to a queue. Process each course by removing it from the queue and decreasing the in-degree of all courses that depend on it. If a course's in-degree becomes zero, add it to the queue. If we process all courses, the graph is acyclic; otherwise, a cycle exists.
Test Your Knowledge
Login to take the complexity quiz and track your progress
Complexity Analysis
Time Complexity: O(V + E) We process each course once and traverse each prerequisite edge once. Building the graph and in-degree array takes O(V + E) time
Space Complexity: O(V + E) We need space for the adjacency list O(V + E), in-degree array O(V), and queue O(V) for BFS traversal
What We've Learned
- Cycle detection via topological sort: When a problem asks if tasks with dependencies can be completed or if an ordering exists, recognize this as a directed acyclic graph (DAG) verification problem - use either Kahn's algorithm (BFS with in-degree tracking) or DFS with coloring to detect cycles, as cycles make topological ordering impossible.
- In-degree tracking pattern: Build an in-degree array counting incoming edges for each node, then use a queue initialized with all zero in-degree nodes - as you process nodes, decrement in-degrees of neighbors and add newly zero in-degree nodes to the queue; if you process all nodes, no cycle exists.
- Adjacency list construction: Convert the prerequisite pairs into an adjacency list representation (HashMap or array of lists) rather than using an adjacency matrix - this gives O(V + E) space instead of O(V²) and allows efficient neighbor iteration, critical when edges are sparse relative to possible connections.
- Three-state DFS coloring: For the DFS approach, use three states (unvisited, visiting, visited) to track node status - if you encounter a node in the 'visiting' state during DFS, you've found a back edge indicating a cycle; this is more reliable than just tracking visited nodes which can miss cycles in disconnected components.
- Complete traversal verification: A critical mistake is assuming no cycle exists just because DFS/BFS completes - you must verify that all N nodes were processed (count == numCourses in BFS, or all nodes marked visited in DFS), as disconnected components with cycles might be missed if you only start from one node.
- Dependency resolution systems: This pattern appears in build systems (Maven, Gradle), package managers (npm, pip), task schedulers, and database transaction ordering - any system where operations have prerequisites needs cycle detection to ensure valid execution order and prevent deadlocks.
Related Concepts and Problems to Practice
This is the exact problem being analyzed (Leetcode 207). It requires detecting cycles in a directed graph using topological sort or DFS, making it the most directly relevant practice problem for understanding course prerequisite scheduling.
This is a natural extension of Course Schedule that not only detects if courses can be completed, but also returns the actual ordering. It reinforces topological sort implementation and cycle detection while adding the complexity of constructing the valid course sequence.
Test Your Understanding
Why is graph the right data structure for this problem?
Select an answer to see the explanation
Question Timeline
See when this question was last asked and where, including any notes left by other candidates.
Early August, 2026
Early July, 2026
Early July, 2026
Hello Interview Premium
Your account is free and you can post anonymously if you choose.