53.课程表

0 阅读2分钟

题目链接

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程  bi 。

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。

解法1 dfs检测

思路

图论的建模一般使用邻接表或者邻接矩阵,而这题边比较少,所以适合邻接表。

首先对课表进行建模,建完之后去检测是否成环。

关键是如何判定成环呢?

我们可以使用一个数组来记录当前课表的状态,有三种状态:

  • 0 表示正常
  • 1 表示正在访问
  • 2 表示已经访问完毕

在遍历课表的时候,去查询该课程邻接表里的状态,如果出现 1 则说明成环,直接返回 false 即可。遍历完毕说明正常,返回 true

代码

function canFinish(numCourses: number, prerequisites: number[][]): boolean {
    const map = new Array(numCourses).fill(0).map(() => []);
    for (let [to, from] of prerequisites) {
        map[from].push(to);
    }

    const visited = new Array(numCourses).fill(0);
    const hasCycle = (node) => {
        if (visited[node] === 1) return true;
        if (visited[node] === 2) return false;

        visited[node] = 1;
        for (let course of map[node]) {
            if (hasCycle(course)) return true;
        }
        visited[node] = 2;
        return false;
    };

    for (let i = 0; i < numCourses; i++) {
        if (hasCycle(i)) return false;
    }
    return true;
};

时空复杂度

n 代表课程数,m 代表边数

时间复杂度:O(n + m)

空间复杂度:O(n + m)

解法2 拓扑排序

思路

还是需要先建图,同样使用邻接表。拓扑排序需要检查节点的入度,所以还需要一个数组来保存课程的入度。

当课程入度为 0 的时候,说明该课程没有前置课程,可以直接学习。在学习完这个课程之后,其后置课程的入度都需要减少,当后续课程的入度为 0 时,此时需要进入队列进行学习。

如何判定是否成环呢?已学习的课程是否等于课程数量,如果不等于,说明无法完成学习。

代码

function canFinish(numCourses: number, prerequisites: number[][]): boolean {
    const map = new Array(numCourses).fill(0).map(() => []);
    const inDegree = new Array(numCourses).fill(0);
    for (let [to, from] of prerequisites) {
        map[from].push(to);
        inDegree[to]++;
    }

    const queue = [];
    for (let i = 0; i < inDegree.length; i++) {
        if (inDegree[i] === 0) {
            queue.push(i);
        }
    }

    let cnt = 0;
    while (queue.length) {
        cnt++;
        const course = queue.shift();
        for (let node of map[course]) {
            inDegree[node]--;
            if (inDegree[node] === 0) {
                queue.push(node);
            }
        }
    }

    return cnt === numCourses;
};

时空复杂度

时间复杂度:O(n + m)

空间复杂度:O(n + m)