LeetCode-207-课程表
207. 课程表
难度中等
你这个学期必须选修 numCourses
门课程,记为 0
到 numCourses - 1
。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites
给出,其中 prerequisites[i] = [ai, bi]
,表示如果要学习课程 ai
则 必须 先学习课程 bi
。
- 例如,先修课程对
[0, 1]
表示:想要学习课程0
,你需要先完成课程1
。
请你判断是否可能完成所有课程的学习?如果可以,返回 true
;否则,返回 false
。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
示例 2:
输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。
提示:
1 <= numCourses <= 105
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
-
prerequisites[i]
中的所有课程对 互不相同
拓扑排序问题
根据依赖关系,构建邻接表、入度数组。
选取入度为 0 的数据,根据邻接表,减小依赖它的数据的入度。
找出入度变为 0 的数据,重复第 2 步。
直至所有数据的入度为 0,得到排序,如果还有数据的入度不为 0,说明图中存在环。
class Solution {
// 一个node,就是一个课程
// name是课程的编号
// in是课程的入度
public static class Node {
public int name;
public int in;
public ArrayList<Node> nexts;
public Node(int n) {
name = n;
in = 0;
nexts = new ArrayList<>();
}
}
public static boolean canFinish(int numCourses, int[][] prerequisites) {
if (prerequisites == null || prerequisites.length == 0) {
return true;
}
HashMap<Integer, Node> nodes = new HashMap<>();
for (int[] arr : prerequisites) {
int to = arr[0];
int from = arr[1];
if (!nodes.containsKey(to)) {
nodes.put(to, new Node(to));
}
if (!nodes.containsKey(from)) {
nodes.put(from, new Node(from));
}
Node t = nodes.get(to);
Node f = nodes.get(from);
f.nexts.add(t);
t.in++;
}
int needPrerequisiteNums = nodes.size();
Queue<Node> zeroInQueue = new LinkedList<>();
for (Node node : nodes.values()) {
if (node.in == 0) {
zeroInQueue.add(node);
}
}
int count = 0;
while (!zeroInQueue.isEmpty()) {
Node cur = zeroInQueue.poll();
count++;
for (Node next : cur.nexts) {
if (--next.in == 0) {
zeroInQueue.add(next);
}
}
}
return count == needPrerequisiteNums;
}
}
拓扑排序问题的解决办法是主要是循环执行以下两步,直到不存在入度为0的顶点为止。
-
- 选择一个入度为0的顶点并输出之;
-
- 从网中删除此顶点及所有出边。
循环结束后,若输出的顶点数小于网中的顶点数,则输出“有回路”信息,即无法完成所有任务;否则输出的顶点序列就是一种拓扑序列,即可以完成所有任务。
// AOV 网的拓扑排序
func canFinish(n int, pre [][]int) bool {
in := make([]int, n)
frees := make([][]int, n)
next := make([]int, 0, n)
for _, v := range pre {
in[v[0]]++
frees[v[1]] = append(frees[v[1]], v[0])
}
for i := 0; i < n; i++ {
if in[i] == 0 {
next = append(next, i)
}
}
for i := 0; i != len(next); i++ {
c := next[i]
v := frees[c]
for _, vv := range v {
in[vv]--
if in[vv] == 0 {
next = append(next, vv)
}
}
}
return len(next) == n
}