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.
Asked at:
DoorDash
Cloudflare
Uber
Meta
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.
def can_finish(num_courses, prerequisites):"""Determine if all courses can be completed using DFS cycle detection.Brute force approach: may revisit nodes multiple times during traversal."""# Build adjacency list: course -> list of prerequisitesgraph = {i: [] for i in range(num_courses)}for course, prereq in prerequisites:graph[course].append(prereq)# Track visiting state: 0=unvisited, 1=visiting, 2=visitedstate = [0] * num_coursesdef has_cycle(course):# If currently visiting this course, we found a cycleif state[course] == 1:return True# If already fully visited, no cycle from this nodeif state[course] == 2:return False# Mark as visitingstate[course] = 1# Recursively check all prerequisitesfor prereq in graph[course]:if has_cycle(prereq):return True# Mark as visitedstate[course] = 2return False# Check each course for cyclesfor course in range(num_courses):if state[course] == 0:if has_cycle(course):return Falsereturn True
Start course schedule validation using DFS cycle detection
0 / 48
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
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.
from collections import dequedef can_finish(num_courses, prerequisites):"""Determine if all courses can be completed using Kahn's algorithm.Returns True if no cycle exists, False otherwise."""# Build adjacency list and calculate in-degreesgraph = [[] for _ in range(num_courses)]in_degree = [0] * num_coursesfor course, prereq in prerequisites:graph[prereq].append(course)in_degree[course] += 1# Initialize queue with courses that have no prerequisitesqueue = deque()for course in range(num_courses):if in_degree[course] == 0:queue.append(course)# Process courses in topological ordercompleted_count = 0while queue:current = queue.popleft()completed_count += 1# Reduce in-degree for dependent coursesfor neighbor in graph[current]:in_degree[neighbor] -= 1if in_degree[neighbor] == 0:queue.append(neighbor)# If all courses processed, no cycle existsreturn completed_count == num_courses
Start course schedule validation using Kahn's algorithm
0 / 36
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
medium
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.
medium
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?
graph provides the optimal access pattern
It's the only data structure that works
It's the easiest to implement
It uses the least memory
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.
Late February, 2026
DoorDash
Staff
Late February, 2026
Cloudflare
Mid-level
Exact Course Schedule Leetcode problem
Mid December, 2025
Meta
Mid-level
Comments
Hello Interview Premium
Your account is free and you can post anonymously if you choose.