Problem
There are a total of numCourses
courses you have to take, labeled from 0
to numCourses - 1
. You are given an array prerequisites
where prerequisites[i] = [ai, bi]
indicates that you must take course bi
first if you want to take course ai
.
- For example, the pair
[0, 1]
, indicates that to take course0
you have to first take course1
.
Return true
if you can finish all courses. Otherwise, return false
.
Examples
Example 1:
Input:
numCourses = 2, prerequisites =[[1,0]]
Output:
true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.
Example 2:
Input:
numCourses = 2, prerequisites =[[1,0],[0,1]]
Output:
false
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.
Solution
This problem can be converted to finding if a graph contains a cycle.
Method 1 - BFS
This solution uses breath-first search and it is easy to understand.
public boolean canFinish(int numCourses, int[][] prerequisites) {
if (prerequisites == null) {
throw new IllegalArgumentException("illegal prerequisites array");
}
int len = prerequisites.length;
if (numCourses == 0 || len == 0) {
return true;
}
// counter for number of prerequisites
int[] pCounter = new int[numCourses];
for (int i = 0; i<len; i++) {
pCounter[prerequisites[i][0]]++;
}
//store courses that have no prerequisites
LinkedList<Integer> queue = new LinkedList<Integer> ();
for (int i = 0; i<numCourses; i++) {
if (pCounter[i] == 0) {
queue.add(i);
}
}
// number of courses that have no prerequisites
int numNoPre = queue.size();
while (!queue.isEmpty()) {
int top = queue.remove();
for (int i = 0; i<len; i++) {
// if a course's prerequisite can be satisfied by a course in queue
if (prerequisites[i][1] == top) {
pCounter[prerequisites[i][0]]--;
if (pCounter[prerequisites[i][0]] == 0) {
numNoPre++;
queue.add(prerequisites[i][0]);
}
}
}
}
return numNoPre == numCourses;
}
Method 2 - DFS
Thsi problem is very close to Topological Sorting.
public boolean canFinish(int numCourses, int[][] prerequisites) {
if (prerequisites == null) {
throw new IllegalArgumentException("illegal prerequisites array");
}
int len = prerequisites.length;
if (numCourses == 0 || len == 0) {
return true;
}
//track visited courses
int[] visit = new int[numCourses];
// use the map to store what courses depend on a course
HashMap<Integer, ArrayList<Integer>> map = new HashMap<Integer, ArrayList<Integer>> ();
for (int[] a: prerequisites) {
map.putIfAbsent(a[1], new ArrayList<Integer>());
map.get(a[1]).add(a[0]);
}
for (int i = 0; i<numCourses; i++) {
if (!canFinishDFS(map, visit, i))
return false;
}
return true;
}
private boolean canFinishDFS(Map<Integer, List<Integer>> map, int[] visit, int i) {
if (visit[i] == -1)
return false;
if (visit[i] == 1)
return true;
visit[i] = -1;
if (map.containsKey(i)) {
for (int j: map.get(i)) {
if (!canFinishDFS(map, visit, j))
return false;
}
}
visit[i] = 1;
return true;
}