Link: 207. Course Schedule - Medium
Track: NeetCode150
Question
Restate the problem
- Given an integer number of courses and a list of prerequisite pairs
- Each pair
a->bmeans courseamust be taken before courseb - Return whether it is possible to finish all courses
Edge Case
- numCourses = 0 → return true
- Graph has a cycle → return
False
| Method | Approach | Time Complexity | Space Complexity |
|---|---|---|---|
| Method 1 ⭐ | BFS (Topological Sort) | ||
| Method 2 | DFS (Detect Cycle) |
Method 1 - BFS (Topological Sort)
Key idea: Use BFS topological sort: repeatedly take courses with
indegree == 0, and if we can process all courses, then there is no cycle.
Approach
- Build a directed graph where an edge
pre -> course - An
indegreearray to record the number of prerequisites for each course - Initialize a queue with all courses that have
indegree0 - While the queue is not empty:
- Pop one course from the queue (this course is completed)
- For each neighboring course:
- Decrease its
indegree - If
indegreebecomes 0, add it to the queue
- Decrease its
- If all courses are processed, return true; otherwise, return false
Complexity
- Time Complexity:
- Space Complexity:
- e.g., graph =
{0:[1], 1:[]}, store edge
- e.g., graph =
Code
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
degree = [0] * numCourses
graph = defaultdict(list)
for course, pre in prerequisites:
degree[course] += 1
graph[pre].append(course)
queue = deque()
taken = 0
for idx in range(len(degree)):
if degree[idx] == 0:
queue.append(idx)
taken += 1
while queue:
node = queue.popleft()
for nei in graph[node]:
degree[nei] -= 1
if degree[nei] == 0:
queue.append(nei)
taken += 1
return taken == numCoursesMethod 2 - DFS (Detect Cycle)
Key idea:
Use DFS to follow each course’s prerequisite chain and detect whether it forms a cycle.
对每门课向前追踪它的precourse,判断依赖链中是否会形成环。
Approach
- Initialize
preMapto store each course’s prerequisites, since DFS follows the dependency chain backward from a course to its prerequisite courses. - Use DFS to trace each course backward through its prerequisite chain
- Use a
visitingset to record courses in the current recursion path - If a course appears again in
visiting, a cycle exists - After a course is fully checked and no cycle is found, set
preMap[course] = []to avoid repeated work
Complexity
- Time Complexity:
- Space Complexity:
- e.g., graph =
{0:[1], 1:[]}, store edge
- e.g., graph =
Code
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
preMap = defaultdict(list)
for course, pre in prerequisites:
preMap[course].append(pre)
visiting = set()
def dfs(course):
if course in visiting:
return False
if preMap[course] == []:
return True
visiting.add(course)
for pre in preMap[course]:
if not dfs(pre):
return False
visiting.remove(course)
preMap[course] = []
return True
for course in range(numCourses):
if not dfs(course):
return False
return TrueMistake
- BFS topological sort usually builds:
pre -> course - DFS cycle detection usually builds:
course -> pre