[路飞]_leetcode-210-课程表 II

240 阅读3分钟

题目描述

[题目地址]

现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi 。

  • 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。

返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。

示例 1:

输入: numCourses = 2, prerequisites = [[1,0]]
输出: [0,1]
解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。

示例 2:

输入: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
输出: [0,2,1,3]
解释: 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3]

示例 3:

输入: numCourses = 1, prerequisites = []
输出: [0]

 

提示:

  • 1 <= numCourses <= 2000
  • 0 <= prerequisites.length <= numCourses * (numCourses - 1)
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • ai != bi
  • 所有[ai, bi] 互不相同

解题思路

在本题中,我们可以将课程之间的关系抽象成图,每一门课程有几个选修课程,入度就是几。
那么没有依赖的先修课程的课程入度就是 0,我们应该先学入度为 0 的课程,当整个课程学完的时候,需要把依赖于它的课程的入度 -1,这样当某个课程的所有先修课程学完了,它的入度就变成了 0,这其实就是图的拓扑排序的过程。
而那些存在互相为先修课程的课程对,会在图中形成环,它们的入度无法变成 0,所以拓扑排序无法处理到它们。
所以我们可以将本题中的课程关系抽象成图进行拓扑排序,拓扑排序的过程就是学习课程的过程。当拓扑排序完成,排序结果数组中就保存了我们一种可能的学习课程的顺序。此时判断该数组长度是否等于 numCourses,如果相等,则可以学完所有课程,返回排序后的结果数组,否则没法学完所有课程,返回空数组即可。

动画演示

leetcode-210-课程表 II.gif

代码实现

var findOrder = function (numCourses, prerequisites) {
    const inDegree = new Array(numCourses).fill(0);//入度数组
    const map = {};//邻接表
    // 遍历二维数组
    for(let i =0; i < prerequisites.length; i++){
        inDegree[prerequisites[i][0]]++;//求每一堂课的初始入度值
        // 判断当前课已经存在邻接表
        if(map[prerequisites[i][1]]){
            // 添加依赖它的后续课
            map[prerequisites[i][1]].push(prerequisites[i][0])
        }else{
            // 当前课不存在邻接表
            map[prerequisites[i][1]] = [prerequisites[i][0]]
        }
    }
    // 处理入度为0节点存到队列(先进先出)
    const queue = [];
    // 队列初始化
    for(let i = 0; i < inDegree.length; i++){
        if(inDegree[i] == 0) queue.push(i)
    }
    let ans = [];
    while(queue.length){
        const selected = queue.shift();
        ans.push(selected);
        const toEnQueue = map[selected];//当前课程的后续课程
        if(toEnQueue && toEnQueue.length){
            for(let i = 0; i<toEnQueue.length; i++){
                inDegree[toEnQueue[i]]--;
                if(inDegree[toEnQueue[i]] === 0){
                    queue.push(toEnQueue[i]);
                }
            }
        }
    }
    if(ans.length == numCourses) return ans;
    return [];
};

至此我们就完成了leetcode-210-课程表 II