Neetcode - Course Schedule
Code is communication.
Course Schedule
You are given an array prerequisites where prerequisites[i] = [a, b] indicates that you must take course b first if you want to take course a.
The pair [0, 1], indicates that must take course 1 before taking course 0.
There are a total of numCourses courses you are required to take, labeled from 0 to numCourses - 1.
Return true if it is possible to finish all courses, otherwise return false.
Input: numCourses = 2, prerequisites = [[0,1]]
Output: true
Explanation: First take course 1 (no prerequisites) and then take course 0.
Input: numCourses = 2, prerequisites = [[0,1],[1,0]]
Output: false
Explanation: In order to take course 1 you must take course 0, and to take course 0 you must take course 1. So it is impossible.
This question is trickier than previous graph problems like Neetcode - Pacific Atlantic Water Flow and Neetcode - Clone Graph . The key insight here is the need to track three distinct states in the visited array. Let’s dive into the code to understand this better.
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> visited(numCourses, 0);
vector<vector<int>> graph(numCourses);
for (auto& pre: prerequisites) {
graph[pre[1]].push_back(pre[0]);
}
for (int i = 0; i < numCourses; ++i) {
if (dfs(i, graph, visited)) {
return false;
}
}
return true;
}
bool dfs(int node, vector<vector<int>>& graph, vector<int>& visited) {
if (visited[node] == 1) return true;
if (visited[node] == 2) return false;
visited[node] = 1;
for (int neighbor : graph[node]) {
if (dfs(neighbor, graph, visited)) {
return true;
}
}
visited[node] = 2;
return false;
}
};
DFS - CSY
First, we create two arrays: one is a one-dimensional array to track the state of each node, and the other is a two-dimensional array that stores the neighbors of each node.
The key part is the recursive DFS function. In this function, nodes marked with state 1 indicate they are currently being visited (i.e., part of the current traversal path), which helps detect cycles. Nodes marked with state 2 indicate they have been fully traversed with no cycles found along that path. When a node is visited for the first time, it is marked as state 1 (visiting), and then the DFS proceeds recursively to traverse all its neighbors. For example:
Input: numCourses = 4, prerequisites = [[1, 0], [2, 1], [3, 2]]
Start
- DFS at Course 0 → visited[0] = 1 (visiting)
- DFS Course 1 → visited[1] = 1 (visiting)
- DFS Course 2 → visited[2] = 1 (visiting)
- DFS Course 3 → visited[3] = 1 (visiting)
Backtrack
- No children → visited[3] = 2 (done)
- Back to Course 2 → visited[2] = 2 (done)
- Back to Course 1 → visited[1] = 2 (done)
- Back to Course 0 → visited[0] = 2 (done)
After constructing the graph as an adjacency list (or array), we begin traversing from course 0 through to course numCourses - 1. During this traversal, we perform backtracking to detect if any course is involved in a cycle with other courses. That's it.