LeetCode 207. Course Schedule
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.
click to show more hints.
经过分析,这道题相当于判断所给有向图中是否有环。其所给图表示方法为邻接表,通常使用DFS或BFS遍历图,需要图以邻接矩阵的形式表示。因此此题需要先把邻接表表示转变为“类”邻接矩阵表示。再使用DFS或BFS遍历,若遍历到重复的顶点,则说明有环。
Java代码如下:
//BFS
public class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
ArrayList[] graph = new ArrayList[numCourses];
int[] degree = new int[numCourses];//记录顶点的入度
Queue queue = new LinkedList();
int count=0;//每有一门课程可以修习,count++
for(int i=0;i<numCourses;i++)
graph[i] = new ArrayList();
//邻接表转邻接矩阵
for(int i=0; i<prerequisites.length;i++){
degree[prerequisites[i][1]]++;//入度+1
graph[prerequisites[i][0]].add(prerequisites[i][1]);//相当于邻接矩阵的一行,从顶点prerequisites[i][0]出,顶点prerequisites[i][1]入
}
//对于入度为0的顶点,说明无需先修课程,可以被选作为图遍历开始的顶点,入队列
for(int i=0; i<degree.length;i++){
if(degree[i] == 0){
queue.add(i);
count++;
}
}
while(queue.size() != 0){
int course = (int)queue.poll();
//对于课程course,若无后续课程,即也无出度,则graph[course].size()为0,直接跳过。
//若有后续课程,则graph[course].size()>0。将其后续课程graph[course].get(i)的入度减1。若后续课程的前续课程全部修完,则入度degree减为0,后续课程可以进行修习count++。
for(int i=0; i<graph[course].size();i++){
int pointer = (int)graph[course].get(i);
degree[pointer]--;
if(degree[pointer] == 0){
queue.add(pointer);
count++;
}
}
}
if(count == numCourses)//可以修习的课程数量=全部课程数量
return true;
else
return false;
}
}
//DFS
public class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
ArrayList[] graph = new ArrayList[numCourses];
for(int i=0;i<numCourses;i++)
graph[i] = new ArrayList();
boolean[] visited = new boolean[numCourses];//默认为false,表示顶点未遍历
//邻接表转邻接矩阵
for(int i=0; i<prerequisites.length;i++){
graph[prerequisites[i][1]].add(prerequisites[i][0]);
}
//从每一个顶点出发,都不会形成环,说明才无环
for(int i=0; i<numCourses; i++){
if(!dfs(graph,visited,i))
return false;
}
return true;
}
private boolean dfs(ArrayList[] graph, boolean[] visited, int course){
if(visited[course])
return false;//所遍历的顶点已经被遍历过,说明有环
else
visited[course] = true;;
//遍历该节点指向的其他节点,若后代节点中存在该节点,则表示有环
for(int i=0; i<graph[course].size();i++){
if(!dfs(graph,visited,(int)graph[course].get(i)))
return false;
}
visited[course] = false;//重置为未遍历状态,供下一次变换初始节点遍历使用
return true;
}
}