Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

课程表问题 #72

Open
xszi opened this issue Jan 11, 2021 · 1 comment
Open

课程表问题 #72

xszi opened this issue Jan 11, 2021 · 1 comment

Comments

@xszi
Copy link
Owner

xszi commented Jan 11, 2021

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

在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]

给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?

示例 1:

输入: 2, [[1,0]] 
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。

示例 2:

输入: 2, [[1,0],[0,1]]
输出: false

解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。

提示:

  • 输入的先决条件是由 边缘列表 表示的图形,而不是 邻接矩阵
  • 你可以假定输入的先决条件中没有重复的边
  • 1 <= numCourses <= 10^5

leetcode

@xszi
Copy link
Owner Author

xszi commented Jan 11, 2021

题解来自瓶子君课程表问题

拓扑排序(有向无环图)

使用广度优先遍历

例如:

输入: 5, [[4,2],[4,3],[2,0],[2,1]]

image

使用 邻接表 来表示有向图中各个节点的依赖关系,同时维护一个入度表,则入度表中入度为 0 的节点所表示的课程是可以立即开始学习的(没有先决条件条件或先觉条件已完成)

所以:

  • 创建一个队列,并将临接表中所有入度为 0 的节点放入队列中
  • 若队列非空,则从队列中出队第一个节点,numCourse — (学习该课程),然后将将依赖该课程所有临接节点的入度减 1
  • 若减 1 后节点入度为 0,则该课程又是可立即学习课程,将该节点添加到队尾
  • 若减 1 后节点入度不为 0 ,则继续遍历下一节点
  • 当队列为空,检查 numCourses === 0 (所有课程是否全部学习结束)即可
let canFinish = function(numCourses, prerequisites) {
    // 如果没有先决条件,即所有的课程均没有依赖关系
    // 直接返回 true
    if (prerequisites.length === 0) {
        return true
    }

    // 维护入度表
    let inDegree = new Array(numCourses).fill(0)
    // 维护临接表
    let adj = new Map()
    
    for (let e of prerequisites) {
        inDegree[e[0]]++
        if(!adj.has(e[1])) adj.set(e[1], [])
        let vEdge = adj.get(e[1])
        vEdge.push(e[0])
    }

    let queue = []
    // 首先加入入度为 0 的结点
    for (let i = 0; i < numCourses; i++) {
        if (inDegree[i] === 0) {
            queue.push(i)
        }
    }

    while (queue.length > 0) {
        // 从队首移除
        var v = queue.shift() 
        // 出队一门课程
        numCourses--
        if(!adj.has(v)) continue
        // 遍历当前出队结点的所有临接结点
        for(let w of adj.get(v)) {
            inDegree[w]--
            if (inDegree[w] === 0) {
                queue.push(w)
            }
        }
    }
    return numCourses === 0
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant