你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。
[0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。示例 2:
输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。检测有没有环,如果两个课程之间相互依赖,比如1依赖0,0依赖1,则无法完成学习
把每门课程看作图中的一个节点,先修关系 [a, b] 表示 b → a 的有向边
构建数组,存放每门课程的前置依赖数量(入度)
构建队列,入度为0的课程放进队列,依次学习,每学完一门课程,把他的入度减1,入度为0时,把它推入队列可以进行学习,最终检测学完的数量是否等于课程的数量
//检测有没有环,有没有课程之间是相互依赖的
var canFinish = function(numCourses, prerequisites) {
//课程的依赖关系
let courseList = Array.from({length: numCourses}, () => []);
//每个课程的前置依赖数量
let indegree = new Array(numCourses).fill(0);
for (let [course, prev] of prerequisites) {
courseList[prev].push(course);
indegree[course]++;
}
//没有前置依赖的课程
let queue = [];
for (let i = 0; i < numCourses; i++) {
if (indegree[i] == 0) {
queue.push(i)
}
}
let learned = 0;
while (queue.length) {
let course = queue.shift();
learned++;
//检查接下来可以学习什么课
for (let nextCourse of courseList[course]) {
indegree[nextCourse]--;
if (indegree[nextCourse] == 0) {
queue.push(nextCourse)
}
}
}
return learned == numCourses
};