210. 课程表 II(Course Schedule II)¶
频次 ★★★★ · 难度 🟡 · 高频:字节
题目¶
和 207 相同,但不仅判断是否有环,还要求返回一个拓扑排序结果。
示例:
思路¶
Kahn 算法:在 BFS 拓扑排序的基础上,每次出队时将节点加入结果数组。如果最终结果长度 == n 则返回结果,否则说明有环返回空数组。
代码¶
public int[] findOrder(int numCourses, int[][] prerequisites) {
List<Integer>[] graph = new List[numCourses];
int[] indegree = new int[numCourses];
for (int i = 0; i < numCourses; i++) graph[i] = new ArrayList<>();
for (int[] p : prerequisites) {
graph[p[1]].add(p[0]);
indegree[p[0]]++;
}
Queue<Integer> q = new ArrayDeque<>();
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0) q.offer(i);
}
int[] res = new int[numCourses];
int idx = 0;
while (!q.isEmpty()) {
int cur = q.poll();
res[idx++] = cur;
for (int next : graph[cur]) {
if (--indegree[next] == 0) q.offer(next);
}
}
return idx == numCourses ? res : new int[0];
}
复杂度¶
- 时间:O(n + m)
- 空间:O(n + m)
边界条件¶
- 空依赖:返回任意顺序(0,1,2,...,n-1 即可)
- 有环:返回空数组
new int[0] - 单节点:返回
[0]
变式¶
易错点¶
- 顺序不唯一:拓扑排序的结果不是唯一的,只要满足依赖关系即可。面试时说"任意一种拓扑序"
- 返回
new int[0]而不是null——题目要求空数组 - 和 207 的代码几乎一致,只需额外加一个数组记出队顺序
面试追问¶
- 要输出字典序最小的拓扑序? BFS 的队列改为优先队列,每次取编号最小的入度为 0 节点
- DFS 后序遍历的逆序 = 拓扑序? 是的,DFS 在节点标记完成后入栈,最后逆序输出。对比 Kahn 算法的"正序"思路,展示两种方法
关联题¶
- 同套路:207. 课程表 —— 判环版
- 进阶:787. K 站中转内最便宜的航班 —— 带约束的最短路径
- 知识点:拓扑排序输出模板见图