试题
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?
Example 1:
Input: 2, [[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: 2, [[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.
代码
有以下思路:
1、对于没有入度出度的节点可以直接完成,对于没有入度的节点也可以直接完成。
2、有入度的节点必须要依赖的节点都完成了,才能够完成。我们可以统计每个节点的依赖完成数量。
3、使用宽度优先,先完成1中节点,然后当2中节点的依赖完成后才能完成。
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
if(prerequisites.length == 0) return true;
HashSet<Integer> start = new HashSet<>();
HashMap<Integer, ArrayList<Integer>> graph = new HashMap<>();
Stack<Integer> stack = new Stack<>();
int[] sum = new int[numCourses];
for(int i = 0; i < numCourses; i++){
start.add(i);
}
for(int[] e : prerequisites){
sum[e[1]]++;
if(start.contains(e[1])){
start.remove(e[1]);
}
if(graph.containsKey(e[0])){
graph.get(e[0]).add(e[1]);
}else{
ArrayList<Integer> temp = new ArrayList<>();
temp.add(e[1]);
graph.put(e[0], temp);
}
}
if(start.size() == 0){
return false;
}
for(int s : start){
stack.push(s);
}
int count = 0;
while(!stack.isEmpty()){
int size = stack.size();
for(int i = 0; i < size; i++){
int cur = stack.pop();
count++;
if(graph.containsKey(cur)){
ArrayList<Integer> nxt = graph.get(cur);
for(int n : nxt){
sum[n]--;
if(sum[n] == 0){
stack.push(n);
}
}
}
}
}
if(count == numCourses){
return true;
}
return false;
}
}
另外其实这题有个特点是如果无法完成,那么说明图中存在一个环。所以可快速判断图中是否有环。
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
if (numCourses == 0 || prerequisites == null || prerequisites.length == 0) return true; // ??
// Index of this list is a course and its values are the dependencies (children)
List<List<Integer>> courseDependency = new ArrayList<>(numCourses);
for (int i = 0; i < numCourses; i++)
courseDependency.add(new ArrayList<>());
/*
create following courseDependency arraylist for each index (course)
0: [1,2],
1: [2],
2: []
*/
for (int i = 0; i < prerequisites.length; i++) {
courseDependency.get(prerequisites[i][0]).add(prerequisites[i][1]);
}
// use state int array to represent current status of visiting for each node
// 0: not visited yet, 1: currently visiting (in recursion stack frame), 2: already visited
int[] state = new int[numCourses];
for (int i = 0; i < numCourses; i++) {
if (!dfs(i, courseDependency, state)) {
return false; // Cycle found
}
}
// no cycle found
return true;
}
private boolean dfs(int course, List<List<Integer>> courseDependency, int[] state) {
state[course] = 1; // currently visiting
List<Integer> dependencies = courseDependency.get(course);
for (int children: dependencies) {
if (state[children] == 1) // If any children is also being currently visiting, then cycle is detected
return false;
if (state[children] == 0) { // Not visted yet
if (!dfs(children, courseDependency, state))
return false;
}
}
state[course] = 2; // done visiting
return true; // no cycle, backtrack to caller
}
}