一、题目
二、思路
1.判断题型
通常遇到先修、先选、前置这些带有“前置条件”的关键词的时候,我们就要考虑到拓扑排序了
2.什么是拓扑排序?
观察上图,这是一张有向无环图,也是满足拓扑排序的图。由定义,一条有向边(u,v),在拓扑排序中始终满足u在v的前面。
在上图中也就是0,1,2,3,4,5这样的排序被称为拓扑排序。
3.解题方法
拓扑排序就像是队列,一层一层进行推进。
1. 用map记录每个节点的入度,入度为0的先进队
2. 用map记录两个节点的relation,用空间换时间,方便查找关系
3. 经过一次while循环后判断最新的入度为0的节点并且入队
4. 队列大小为0后遍历存储入度的map,如果value全部为0则证明可以进行拓扑排序
4.代码
public class P207_CourseSchedule {
//力扣代码
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
private Map<Integer, Integer> inDegree = new HashMap<>(); //存储每个节点的入度
private Map<Integer, List<Integer>> relation = new HashMap<>(); //存储节点之间的关系,方便查找,key为当前节点,value为下个节点
public boolean canFinish(int numCourses, int[][] prerequisites) {
//初始化入度map,先把所有节点添加进去
for (int i = 0; i < numCourses; i++) {
inDegree.put(i, 0);
}
//初始化relation的map
for (int i = 0; i < prerequisites.length; i++) {
int cur = prerequisites[i][1];
int next = prerequisites[i][0];
//更新入度
inDegree.put(next, inDegree.get(next) + 1);
//更新联系
if (!relation.containsKey(cur)) {
//已当前节点为key,初始化
relation.put(cur, new ArrayList<>());
}
//存储当前节点的下个节点
relation.get(cur).add(next);
}
//初始化队列
Queue<Integer> queue = new LinkedList<>();
for (int key : inDegree.keySet()) {
if (inDegree.get(key) == 0) { //入度为0的节点入队
queue.offer(key);
}
}
//更新入度
while (!queue.isEmpty()) {
//拿到当前节点
Integer cur = queue.poll();
//这个节点的relation可能为空,也就是说他是一个独立的节点
if (!relation.containsKey(cur)) {
continue; //那么久直接跳过
}
//遍历当前节点的下个节点,让他们的入度-1
for (int next : relation.get(cur)) {
inDegree.put(next, inDegree.get(next) - 1);
if (inDegree.get(next) == 0) { //入度为0则入队
queue.offer(next);
}
}
}
//遍历inDegree
for (int key : inDegree.keySet()) {
if (inDegree.get(key) != 0) {
return false;
}
}
return true;
}
}
//leetcode submit region end(Prohibit modification and deletion)
public static void main(String[] args) {
//测试代码
Solution solution = new P207_CourseSchedule().new Solution();
}
}