1.题目
LeetCode: 207. 课程表
【medium】
2.解题
方法一:DFS
参考:
https://leetcode-cn.com/problems/course-schedule/solution/ke-cheng-biao-by-leetcode-solution/
java:
class Solution {
List<List<Integer>> edges;
int[] visited;
boolean valid = true;
public boolean canFinish(int numCourses, int[][] prerequisites) {
edges = new ArrayList<List<Integer>>();
for (int i = 0; i < numCourses; ++i) {
edges.add(new ArrayList<Integer>());
}
visited = new int[numCourses];
for (int[] info : prerequisites) {
edges.get(info[1]).add(info[0]);
}
for (int i = 0; i < numCourses && valid; i++) {
if (visited[i] == 0) dfs(i);
}
return valid;
}
public void dfs(int i) {
visited[i] = 1;
for (int j : edges.get(i)) {
if (visited[j] == 0) {
dfs(j);
if (!valid) return;
} else if (visited[j] == 1) {
valid = false;
return;
}
}
visited[i] = 2;
}
}
方法二:入度表(BFS)
参考:
https://leetcode-cn.com/problems/course-schedule/solution/course-schedule-tuo-bu-pai-xu-bfsdfsliang-chong-fa/
可以将本题转换成是否存在有向无环图的问题,因为安排课程的结果是一个拓扑排序不应该存在有向无环图,否则无法安排课程。
故首先统计每个节点的入度,并生成入度表,入度为0的节点(课程)没有前置课程。然后借助队列将所有入度为0的节点入队。当队列非空时,依次将队首节点出队,并且将与其邻接的节点入度-1,当邻接节点入度-1后为0则代表已完成前置课程,将其入队,以此类推,每次出队时将numCourses–,直至最后如果numCourses为0则代表可以完成所有课程,否则返回false。
java:
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int[] indegrees = new int[numCourses];
Queue<Integer> queue = new LinkedList<>();
List<List<Integer>> edges = new ArrayList<>();
for (int i = 0; i < numCourses; i++) edges.add(new ArrayList<>());
for (int[] info : prerequisites) {
indegrees[info[0]]++;
edges.get(info[1]).add(info[0]);
}
for (int i = 0; i < numCourses; i++) {
if (indegrees[i] == 0) queue.add(i);
}
while (!queue.isEmpty()) {
int pre = queue.poll();
numCourses--;
for (int cur : edges.get(pre)) {
if (--indegrees[cur] == 0) queue.add(cur);
}
}
return numCourses == 0;
}
}
时间复杂度 O(N + M) 遍历一个图需要访问所有节点和所有临边,N 和 M 分别为节点数量和临边数量;
空间复杂度 O(N + M) 为建立邻接表所需额外空间,edges 长度为 N ,并存储 M 条临边的数据。
疑问
edges.get(info[1]).add(info[0]);
该语句的执行结果是每门课程依赖他的课程列表
比如:
4
[[1,0],[2,0],[3,0],[3,1]]
结果是
[[1, 2, 3], [3], [], []]