There are a total of n courses you have to take, labeled from 0
to n - 1
.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
For example:
2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
2, [[1,0],[0,1]]
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.
Note:
- The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
- You may assume that there are no duplicate edges in the input prerequisites.
Hints:
首先用的是拓扑消除法。用matrix保存所有出度,indegree保存每个课的入度个数。queue弹进所有入度为0的课。如果queue不为空,弹出一个课,count+1,遍历所有出度,如果为1,相应的入度-1,如果某一个入度为零了,立即入栈。最后返回count == nomCourse,即是否消除完所有的入度。代码如下:
- This problem is equivalent to finding if a cycle exists in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
- Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
- Topological sort could also be done via BFS.
public class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int[][] matrix = new int[numCourses][numCourses];
int[] indegree = new int[numCourses];
for (int[] pair: prerequisites) {
indegree[pair[0]]++;
matrix[pair[1]][pair[0]] = 1;
}
Queue<Integer> queue = new LinkedList<Integer>();
for (int i = 0; i < numCourses; i ++) {
if (indegree[i] == 0) queue.offer(i);
}
int count = 0;
while (!queue.isEmpty()) {
int course = queue.poll();
count ++;
for (int i = 0; i < numCourses; i ++) {
if (matrix[course][i] == 1) {
if (--indegree[i] == 0) {
queue.offer(i);
}
}
}
}
return count == numCourses;
}
}
另一种方法,深度优先遍历。设置marked标记此序列已经被遍历过,如果被标记过,恰好stacked[course]为true的话说明stack了,loop设置为true,最后返回!loop。代码如下:
public class Solution {
boolean[] marked;
boolean[] stacked;
boolean loop;
public boolean canFinish(int numCourses, int[][] prerequisites) {
ArrayList[] lists = new ArrayList[numCourses];
marked = new boolean[numCourses];
stacked = new boolean[numCourses];
loop = false;
for (int i = 0; i < numCourses; i ++) {
lists[i] = new ArrayList<Integer>();
}
for (int[] pair: prerequisites) {
lists[pair[0]].add(pair[1]);
}
for (int i = 0; i < numCourses; i ++) {
if (!marked[i]) {
helper(lists, i);
}
}
return !loop;
}
private void helper(List<Integer>[] lists, int course) {
stacked[course] = true;
marked[course] = true;
if (loop) return;
for (int i = 0; i < lists[course].size(); i ++) {
int index = lists[course].get(i);
if (!marked[index]) {
helper(lists, index);
} else if (stacked[index]) {
loop = true;
}
}
stacked[course] = false;
}
}