力扣题/图论/课程表

课程表

力扣原题

你这个学期必须选修 numCourses 门课程,记为 0numCourses - 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 。这是不可能的。

javascript 复制代码
/**
 * @param {number} numCourses
 * @param {number[][]} prerequisites
 * @return {boolean}
 */
var canFinish = function(numCourses, prerequisites) {
    // 构建节点关系    key: 当前节点, value:当前节点指向的所有节点
    const edges = buildEdges(prerequisites)

    let valid = true
    const visited = new Array(numCourses).fill(0)

    // 深度遍历,判断是否存在环
    function dfs(i) {
        const edge = edges[i]
        if(!edge) return
        visited[i] = 1 // 访问中
        for(const nextNode of edge) {
            if(visited[nextNode] === 0) {
                dfs(nextNode)
                if(!valid) return
            } else if(visited[nextNode] === 1) {
                // 存在环
                valid = false;
                return
            }
        }

        visited[i] = 2; // 已访问
    }

    for(let i = 0; i < numCourses; i++) {
        if(!visited[i]) {
            dfs(i)
        }
    }

    return valid
};

// 构建边的关系
function buildEdges(prerequisites) {
    // 根据节点数量,初始化所有的节点的相邻的空数组(用于记录指向的节点)
    const edgeMap = {}

    for(const [node, preNode] of prerequisites) {
        if(!edgeMap[preNode]) {
            edgeMap[preNode] = []
        }
        edgeMap[preNode].push(node)
    }

    return edgeMap
}

解题思路

核心思路是构建有向图,然后深度遍历判断是否存在环存在环则无法进行拓扑排序,也说明无法完成所有课程的学习

  1. prerequisites中,每一项表示[课程, 先修课程]。遍历prerequisites转化为key先修课程value课程的数组构建有向图
  2. 通过visited数组记录每个节点的访问状态,0:未访问,1:访问中,2:已访问,遍历所有节点,进行深度遍历dfs
  3. 深度遍历时,只需要判断,是否在遍历过程中,遇到访问中的节点即可,如果遇到访问中的节点,证明存在环。(如果不存在环,深度遍历过程中不可能访问到访问中的节点)
相关推荐
海石28 分钟前
单调栈复健,顺便,牺牲一下吧,空间复杂度!一切献给AC
算法·leetcode
海石29 分钟前
JS击败94%,Hard题想不到动态规划,那就用数组和栈试试
算法·leetcode
多加点辣也没关系2 小时前
JavaScript|第9章:对象 — 基础
开发语言·javascript·ecmascript
学究天人2 小时前
数学公理体系大全:Comprehensive Collection of Mathematical Axiom Systems(卷7)
线性代数·矩阵·动态规划·概率论·图论·抽象代数·拓扑学
杨逢昌工厂6S管理2 小时前
28- 杨逢昌:制造企业仓储6S反复混乱解决方案——四维定置标准化管控体系,让物料混放、通道堵塞等重复性乱象减少90%
大数据·经验分享·笔记·职场和发展·制造·学习方法
alphaTao3 小时前
LeetCode 每日一题 2026/7/6-2026/7/12
算法·leetcode
想吃火锅10053 小时前
【leetcode】56.合并区间js
算法·leetcode·职场和发展
imuliuliang3 小时前
可合并堆在多任务调度中的优势与实现技巧7
算法
学究天人3 小时前
数学公理体系大全:Comprehensive Collection of Mathematical Axiom Systems(卷6)
网络·算法·数学建模·动态规划·几何学·图论·拓扑学
后台开发者Ethan3 小时前
setState组件更新
前端·javascript·react