207. 课程表
你这个学期必须选修 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 <= numCourses <= 2000
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同
我先说说我对这道题的思考:
对于算法题,一定要先理解题,然后总结出规律,这点很重要,这道题的关键点就是 numCourses门课程中,一定有可以先完成的课且它不依赖于其他课的完成,这就是这道题解题的关键点。
关键点:一定有可以先完成的课且它不依赖于其他课的完成的课,这样才有可能完成。
var canFinish = function (numCourses, prerequisites) {
// 先修课程如果没有,那么就直接返回true
if (prerequisites.length < 1) {
return true
}
// 一定要先理解题,然后总结出规律,这点很重要,这道题的关键点就是 numCourses门课程中,一定有可以先完成的课且它不依赖于其他课的完成,这是这道题解题的关键点。
// 首先先根据有多少门课程创建数组,初始化值都为0
let inDegree = new Array(numCourses).fill(0)
// 创建map,用于存储 被依赖项和依赖项之间的关系 [ai, bi] 表示如果要学习课程 ai 则 必须 先学习课程 bi 所以 ai是依赖项 bi是被依赖项
let depend = new Map()
for (let e of prerequisites) {
inDegree[e[0]]++ // 这一步说明 每一个依赖项所依赖的课程数,例如3门课,[[1,2],[1,0]] 所以inDegree最后为[0,2,0], 说明课程1依赖了两门课程 这一步创建了依赖项的关系
if (!depend.has(e[1])) { // 这一步说明 每一个被依赖项都被哪些门课程依赖了
depend.set(e[1], []) // 先创建空数组
}
depend.get(e[1]).push(e[0]) // 每一个被依赖项都被哪些门课程依赖了,都会push到数组中
}
let queue = [] // 用来存储那些课程中 不依赖其他的课程的 课程
// 筛选出不依赖于其他课的课程,可以先完成的, queue里面保存的都是可以先完成,不依赖于其他课的课程
for (let i = 0; i < numCourses; i++) {
if (inDegree[i] === 0) {
queue.push(i)
}
}
while (queue.length > 0) {
let q = queue.shift() // 获取不依赖于其他课的课程
numCourses--; // 相应的课程总数减1
if (!depend.has(q)) continue // 如果被依赖项没有q(q是不依赖于其他课的课程)那就退出此次调用,继续下一次的调用
// 如果被依赖项有q(q是不依赖于其他课的课程)
for (let v of depend.get(q)) {
inDegree[v]-- // 这一步操作说明依赖项(依赖的课程)可以上,所以直接减1,因为被依赖项(被依赖的课程是可以上完的),所以依赖项也是可以上完的
if (inDegree[v] === 0) { // 如果依赖项的值为0,说明它可以上完,那么其他依赖于这个依赖项的 也可以上完,所以queue需要push对应的下标值,说明这个下标值代表的课程可以被依赖
queue.push(v)
}
}
}
// 课程能上完,最后的numCourses一定是等于0的,因为queue中存储过的值肯定是所有课程,因为最后得到的都是不依赖于其他课的课程
return numCourses === 0
// 如果完成所有课程的学习,numCourses门课程都是做为依赖项或者被依赖项能完成的课程,才会返回true,否则返回false,所以如果结果是true,while循环会循环numCourses次,numCourses最后会减为0
};
console.log(canFinish(2, [[1, 0]]))
867

被折叠的 条评论
为什么被折叠?



