课程表 II
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 27 ms, 内存: 17.2 MB
/*
思路:
1. 使用拓扑排序算法来解决这个问题。我们需要计算每门课程的入度(需要先修的课程数),并记录每门课程的后续课程。
2. 从入度为0的课程开始,逐一学习这门课程,并将其后续课程的入度减1。
3. 如果某门课程的入度减到0,则说明它可以被学习,继续将其加入学习序列。
4. 最终如果学习了所有课程,返回学习顺序,否则返回空数组。
*/
import java.util.*;
import java.util.stream.*;
public class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
List<Integer> result = new ArrayList<>();
int[] indegree = new int[numCourses];
Map<Integer, List<Integer>> graph = IntStream.range(0, numCourses).boxed().collect(Collectors.toMap(i -> i, i -> new ArrayList<>()));
// 初始化图和入度数组
Arrays.stream(prerequisites).forEach(prereq -> {
int course = prereq[0];
int prereqCourse = prereq[1];
graph.get(prereqCourse).add(course);
indegree[course]++;
});
// 找到所有入度为0的课程
Queue<Integer> queue = IntStream.range(0, numCourses).filter(i -> indegree[i] == 0).boxed().collect(Collectors.toCollection(LinkedList::new));
// 开始学习课程
while (!queue.isEmpty()) {
int course = queue.poll();
result.add(course);
graph.get(course).forEach(nextCourse -> {
indegree[nextCourse]--;
if (indegree[nextCourse] == 0) {
queue.offer(nextCourse);
}
});
}
// 检查是否所有课程都被学习
return result.size() == numCourses ? result.stream().mapToInt(i -> i).toArray() : new int[0];
}
}
解释
方法:
这个题解使用了拓扑排序的方法来安排课程的学习顺序。首先构建一个图和一个入度数组,图用于表示每门课作为先决条件时,会影响哪些课程,入度数组记录每门课程所需的先决条件数量。初始化时,将所有入度为0的课程(即没有先决条件的课程)加入队列。然后进行拓扑排序,每次从队列中取出一个课程,将其加入排序结果中,并减少其影响的课程的入度。如果减少后某课程的入度变为0,则将其加入队列。在遍历完所有课程后,如果排序的课程数量等于总课程数,则返回排序结果,否则说明存在循环依赖,返回空数组。
时间复杂度:
O(V + E)
空间复杂度:
O(V + E)
代码细节讲解
🦆
在构建图和入度数组时,你是如何处理重复的先决条件关系的?例如,如果存在多个相同的 [ai, bi],会对算法的执行或结果产生什么影响?
▷🦆
在拓扑排序的过程中,如果存在多个课程同时入度为0,算法是如何选择下一个课程的?这种选择方式是否会影响最终的课程顺序?
▷🦆
你提到如果最终排序的课程数量不等于总课程数时,将返回空数组。这是否暗示了图中存在环?如何通过算法准确地检测到这种环的存在?
▷