吃完普通的食堂饭菜,回到实验室,继续做一道题!
1、题目描述
2、逻辑分析
这道题涉及到图相关知识,应用到了拓扑排序。
题意解释
- 一共有 n 门课要上,编号为 0 ~ n-1。
- 先决条件 [1, 0],意思是必须先上课 0,才能上课 1。
- 给你 n、和一个先决条件表,请你判断能否完成所有课程。
官方给的题解太抽象了,有另一个题解给的很直观,易理解,放过来:题解:课程表
3、代码演示
public boolean canFinish(int numCourses, int[][] prerequisites) {
// 创建一个哈希映射,用于存储每个课程的入度(即需要先修的课程数量)
Map<Integer, Integer> inDegree = new HashMap<>();
// 初始化每个课程的入度为0
for(int i = 0; i < numCourses; i++){
inDegree.put(i,0);
}
// 创建一个哈希映射,用于存储每个课程的后续课程列表
Map<Integer, List<Integer>> adj = new HashMap<>();
// 遍历先决条件数组
for(int[] relate : prerequisites){
// 当前课程(即需要学习的课程)
int cur = relate[1];
// 后续课程(即当前课程的先决条件)
int next = relate[0];
// 更新后续课程的入度
inDegree.put(next, inDegree.get(next) + 1);
// 如果当前课程的后续课程列表还未初始化,则进行初始化
if(!adj.containsKey(cur)){
adj.put(cur, new ArrayList<>());
}
// 将后续课程添加到当前课程的后续课程列表中
adj.get(cur).add(next);
}
// 创建一个队列,用于存储入度为0的课程
Queue<Integer> queue = new LinkedList<>();
// 将所有入度为0的课程加入队列
for(int key : inDegree.keySet()){
if(inDegree.get(key) == 0){
queue.offer(key);
}
}
// 拓扑排序的主循环
while(!queue.isEmpty()){
// 取出队首的入度为0的课程
int cur = queue.poll();
// 如果当前课程没有后续课程(即没有需要它作为先决条件的课程),则跳过此次循环
if(! adj.containsKey(cur)){
continue;
}
List<Integer> successorList = adj.get(cur);
// 遍历当前课程的后续课程列表
for(int k : successorList){
// 更新后续课程的入度
inDegree.put(k, inDegree.get(k) - 1);
// 如果后续课程的入度变为0,则将其加入队列
if(inDegree.get(k) == 0){
queue.offer(k);
}
}
}
// 遍历所有课程的入度,如果有任何课程的入度不为0,则说明存在环,无法完成所有课程
for(int key : inDegree.keySet()){
if(inDegree.get(key) != 0){
return false;
}
}
// 所有课程的入度都为0,说明不存在环,可以完成所有课程
return true;
}
哈哈,击败百分之十二,笑了!照着打的,看了半天还是不太懂,懂了我下次做估计也做不出来,先放这儿吧,下次再来看!