【算法】课程表

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]]))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值