You are given a total number of courses (n) and a list of prerequisites represented as pairs of course numbers. The prerequisites indicate that to take course prerequisites[i][0]
, you must first complete course prerequisites[i][1]
. It is guaranteed that a valid ordering of courses exists.
You need to determine if it is possible to complete all courses by taking the courses in a valid order (no circular dependencies).
Table of Contents
Example:
Input:
n = 4
prerequisites = [[1, 0], [2, 1], [3, 2]]
Explanation: To take course 1, you need to take course 0 first. To take course 2, you need to take course 1 first, and so on. A valid ordering would be: 0 -> 1 -> 2 -> 3
Output:
true
Input:
n = 2
prerequisites = [[1, 0], [0, 1]]
Explanation: To take course 1, you need to take course 0 first, and to take course 0, you need to take course 1 first. There is a circular dependency, and it is not possible to complete all courses.
Output:
false
Time Complexity:
The time complexity of the solution is O(V + E), where V is the number of courses (vertices) and E is the number of prerequisites (edges).
Space Complexity:
The space complexity of the solution is O(V + E) due to the adjacency list representation of the graph.
Course Schedule C++ Solution:
#include <vector>
#include <queue>
using namespace std;
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> graph(numCourses); // Adjacency list representation of the graph
vector<int> inDegree(numCourses, 0); // In-degree of each course
// Create the graph and calculate the in-degree of each course
for (const auto& edge : prerequisites) {
graph[edge[1]].push_back(edge[0]); // Add directed edge from edge[1] to edge[0]
inDegree[edge[0]]++; // Increment the in-degree of edge[0]
}
queue<int> q;
// Add all courses with in-degree 0 to the queue
for (int i = 0; i < numCourses; i++) {
if (inDegree[i] == 0) {
q.push(i);
}
}
int numTakenCourses = 0;
while (!q.empty()) {
int currentCourse = q.front();
q.pop();
numTakenCourses++;
// Process all dependent courses (outgoing edges)
for (int dependentCourse : graph[currentCourse]) {
inDegree[dependentCourse]--; // Reduce the in-degree of the dependent course
// If the dependent course now has in-degree 0, add it to the queue
if (inDegree[dependentCourse] == 0) {
q.push(dependentCourse);
}
}
}
// If the number of taken courses is equal to the total number of courses, return true
// Otherwise, there must be a cycle in the graph, so return false
return numTakenCourses == numCourses;
}
Explanation of Code:
- We create an adjacency list representation of the graph using the
graph
vector. Each indexi
in thegraph
vector corresponds to a course, and the elements ofgraph[i]
are the courses that depend on coursei
. - We create a vector
inDegree
to keep track of the in-degree of each course. The in-degree of a course is the number of prerequisite courses it has. - We populate the graph and calculate the in-degree for each course based on the given prerequisites.
- We use a queue to perform a Breadth-First Search (BFS) on the graph. Initially, we add all courses with in-degree 0 (no prerequisites) to the queue.
- In each iteration of the BFS, we take a course from the front of the queue, increment the count of taken courses, and process its dependent courses (outgoing edges).
- For each dependent course, we reduce its in-degree since one of its prerequisites (the current course) is taken. If the in-degree becomes 0, we add the dependent course to the queue.
- We repeat the process until the queue is empty.
- Finally, if the number of taken courses is equal to the total number of courses, it means all courses can be completed in a valid order, so we return
true
. Otherwise, there must be a cycle, and it is not possible to complete all courses, so we returnfalse
.