题目
你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
思路
课程安排简化为有向无环图。
队列,将入度为0 的节点入队,当队列非空时候,节点出队同时删除节点周围的边。
删除后会有邻接节点入度为0此时继续入队。
每次出队元素都将课程数减1,当最后课程数为0时课程可以成功安排。因为是一个无环图。
哈希set定义类似于邻接表
arr【0】={0 1 2 }
arr【1】={1 2 3}
记录后继节点
代码
public boolean canFinish(int numCourses, int[][] prerequisites) {
//入度数组
int []indegrees = new int[numCourses];
// 记录每个节点的后继节点,就是邻接表的样式,一个节点后面连接一个数组,数组中记录的后继节点
HashSet<Integer> []adj = new HashSet[numCourses];
//放入索引节点
for(int i=0;i<numCourses;i++){
adj[i] = new HashSet<>();
}
for(int []p:prerequisites){
indegrees[p[0]]++;//入度
adj[p[1]].add(p[0]);//后继节点
}
Queue<Integer> queue = new LinkedList<>();
//加入入度为0的节点
for(int i = 0;i<numCourses;i++){
if(indegrees[i]==0){
queue.add(i);
}
}
//记录已经出队的课程数量
int cnt=0;
while(!queue.isEmpty()){
Integer top = queue.poll();
cnt+=1;
//遍历当前出队节点的所有后继节点
for(int bef:adj[top]){
indegrees[bef]--;//出队后相应连线消失,后继节点的入度要减1
if(indegrees[bef]==0){
queue.add(bef);
}
}
}
return cnt==numCourses;
}