课程表
难度:⭐⭐⭐ 面试高频
考点
- 拓扑排序(BFS Kahn 算法)
- 有向图判环
- 字节面试高频图论题
题目描述
你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses-1。给你一个数组 prerequisites,其中 prerequisites[i] = [a, b] 表示如果你想学课程 a,必须先学课程 b。
判断你是否可以完成所有课程的学习。(等价于:有向图中是否存在环)
函数签名
go
func canFinish(numCourses int, prerequisites [][]int) bool示例
输入:numCourses = 2, prerequisites = [[1,0]]
输出:true(先学 0 再学 1)
输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false(存在环:0→1→0)要求
- 时间复杂度 O(V+E)
提示
BFS 拓扑排序(Kahn 算法)
- 构建邻接表 + 入度数组
- 入度为 0 的节点入队
- 每次出队一个,将其所有邻接节点入度 -1
- 入度变 0 的节点入队
- 最终出队数 == numCourses → 无环 → 可完成
DFS 判环
- 三色标记:白(未访问)、灰(路径中)、黑(已完成)
- 遇到灰色节点 → 有环
参考答案(Go)
点击展开参考答案
go
//go:build ignore
package answer
// BFS 拓扑排序(Kahn 算法)
func canFinish(numCourses int, prerequisites [][]int) bool {
graph := make([][]int, numCourses)
inDegree := make([]int, numCourses)
for _, pre := range prerequisites {
a, b := pre[0], pre[1]
graph[b] = append(graph[b], a)
inDegree[a]++
}
queue := make([]int, 0)
for i := 0; i < numCourses; i++ {
if inDegree[i] == 0 {
queue = append(queue, i)
}
}
count := 0
for len(queue) > 0 {
cur := queue[0]
queue = queue[1:]
count++
for _, next := range graph[cur] {
inDegree[next]--
if inDegree[next] == 0 {
queue = append(queue, next)
}
}
}
return count == numCourses
}