题目链接:课程表
你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
// 注意pre数组的每一维的前后关系别弄反,后者是前者的前置依赖必修课。
int[] beforeClassCounts = new int[numCourses];
List<List<Integer>> dependencyLists = new ArrayList<>();
for (int i = 0; i < numCourses; i++) {
dependencyLists.add(new ArrayList<>());
}
Queue<Integer> queue = new LinkedList<Integer>();
// 将每个课程的入度记录下来
// 将每个节点的 以该节点为前置依赖必修课的课程记录下来
for (int[] pre : prerequisites) {
beforeClassCounts[pre[0]]++;
dependencyLists.get(pre[1]).add(pre[0]);
}
// 将入度为0的课程直接入队,获取以该课程为前置必修课的课程列表,遍历这些列表,将其入度-1。
for (int i = 0;i < numCourses; i++) {
if (beforeClassCounts[i] == 0) {
queue.add(i);
}
}
// 并进行判断,若这些列表中的课程此时的入度为1,即这些课程此时可以修了,将其入队。
while (!queue.isEmpty()){
int FinishedCourse = queue.poll();
// numCourses--; 放前后都可以
for (int cur : dependencyLists.get(FinishedCourse)) {
if ( --beforeClassCounts[cur] == 0) {
queue.add(cur);
}
}
numCourses--;
}
// 因为入队的课程已经修了,总修课程数目-1。
//当没有入度为1的课程时判断此时的已修课程数目与必修总课程numCourse的大小关系,为0则true,否则为false。
return numCourses == 0;
}
}