|
5 | 5 |
|
6 | 6 | ## 题目大意
|
7 | 7 |
|
8 |
| -给定一个整数 `numCourses`,代表这学期必须选修的课程数量,课程编号为 `0` 到 `numCourses - 1`。再给定一个数组 `prerequisites` 表示先修课程关系,其中 `prerequisites[i] = [ai, bi]` 表示如果要学习课程 `ai` 则必须要学习课程 `bi`。 |
| 8 | +**描述**:给定一个整数 $numCourses$,代表这学期必须选修的课程数量,课程编号为 $0 \sim numCourses - 1$。再给定一个数组 $prerequisites$ 表示先修课程关系,其中 $prerequisites[i] = [ai, bi]$ 表示如果要学习课程 $ai$ 则必须要先完成课程 $bi$。 |
9 | 9 |
|
10 |
| -要求:判断是否可能完成所有课程的学习。如果可以,返回 `True`,否则,返回 `False`。 |
| 10 | +**要求**:判断是否可能完成所有课程的学习。如果可以,返回 `True`,否则,返回 `False`。 |
11 | 11 |
|
12 |
| -## 解题思路 |
| 12 | +**说明**: |
| 13 | + |
| 14 | +- $1 \le numCourses \le 10^5$。 |
| 15 | +- $0 \le prerequisites.length \le 5000$。 |
| 16 | +- $prerequisites[i].length == 2$。 |
| 17 | +- $0 \le ai, bi < numCourses$。 |
| 18 | +- $prerequisites[i]$ 中所有课程对互不相同。 |
| 19 | + |
| 20 | +**示例**: |
| 21 | + |
| 22 | +- 示例 1: |
| 23 | + |
| 24 | +```Python |
| 25 | +输入:numCourses = 2, prerequisites = [[1,0]] |
| 26 | +输出:true |
| 27 | +解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。这是可能的。 |
| 28 | +``` |
| 29 | + |
| 30 | +- 示例 2: |
13 | 31 |
|
14 |
| -拓扑排序。 |
| 32 | +```Python |
| 33 | +输入:numCourses = 2, prerequisites = [[1,0],[0,1]] |
| 34 | +输出:false |
| 35 | +解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。 |
| 36 | +``` |
15 | 37 |
|
16 |
| -1. 使用列表 `edges` 存放课程关系图,并统计每门课程节点的入度,存入入度列表 `indegrees`。 |
| 38 | +## 解题思路 |
17 | 39 |
|
18 |
| -2. 借助队列 `queue`,将所有入度为 `0` 的节点入队。 |
| 40 | +### 思路 1:拓扑排序 |
19 | 41 |
|
20 |
| -3. 从队列中选择一个节点,并且让课程数 -1。 |
21 |
| -4. 将该顶点以及该顶点为出发点的所有边的另一个节点入度 -1。如果入度 -1 后的节点入度不为 0,则将其加入队列 `queue`。 |
22 |
| -5. 重复 3~4 的步骤,直到队列中没有节点。 |
23 |
| -6. 最后判断剩余课程数是否为 0,如果为 0,则返回 `True`,否则,返回 `False`。 |
| 42 | +1. 使用哈希表 $graph$ 存放课程关系图,并统计每门课程节点的入度,存入入度列表 $indegrees$。 |
| 43 | +2. 借助队列 $S$,将所有入度为 $0$ 的节点入队。 |
| 44 | +3. 从队列中选择一个节点 $u$,并令课程数减 $1$。 |
| 45 | +4. 从图中删除该顶点 $u$,并且删除从该顶点出发的有向边 $<u, v>$(也就是把该顶点可达的顶点入度都减 $1$)。如果删除该边后顶点 $v$ 的入度变为 $0$,则将其加入队列 $S$ 中。 |
| 46 | +5. 重复上述步骤 $3 \sim 4$,直到队列中没有节点。 |
| 47 | +6. 最后判断剩余课程数是否为 $0$,如果为 $0$,则返回 `True`,否则,返回 `False`。 |
24 | 48 |
|
25 |
| -## 代码 |
| 49 | +### 思路 1:代码 |
26 | 50 |
|
27 | 51 | ```Python
|
28 | 52 | import collections
|
29 | 53 |
|
30 | 54 | class Solution:
|
| 55 | + def topologicalSorting(self, numCourses, graph): |
| 56 | + indegrees = {u: 0 for u in graph} |
| 57 | + for u in graph: |
| 58 | + for v in graph[u]: |
| 59 | + indegrees[v] += 1 |
| 60 | + |
| 61 | + S = collections.deque([u for u in indegrees if indegrees[u] == 0]) |
| 62 | + |
| 63 | + while S: |
| 64 | + u = S.pop() |
| 65 | + numCourses -= 1 |
| 66 | + for v in graph[u]: |
| 67 | + indegrees[v] -= 1 |
| 68 | + if indegrees[v] == 0: |
| 69 | + S.append(v) |
| 70 | + |
| 71 | + if numCourses == 0: |
| 72 | + return True |
| 73 | + return False |
| 74 | + |
31 | 75 | def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
|
32 |
| - indegrees = [0 for _ in range(numCourses)] |
33 |
| - edges = collections.defaultdict(list) |
34 |
| - for x, y in prerequisites: |
35 |
| - edges[y].append(x) |
36 |
| - indegrees[x] += 1 |
37 |
| - queue = collections.deque([]) |
| 76 | + graph = dict() |
38 | 77 | for i in range(numCourses):
|
39 |
| - if not indegrees[i]: |
40 |
| - queue.append(i) |
41 |
| - while queue: |
42 |
| - y = queue.popleft() |
43 |
| - numCourses -= 1 |
44 |
| - for x in edges[y]: |
45 |
| - indegrees[x] -= 1 |
46 |
| - if not indegrees[x]: |
47 |
| - queue.append(x) |
48 |
| - return not numCourses |
| 78 | + graph[i] = [] |
| 79 | + |
| 80 | + for v, u in prerequisites: |
| 81 | + graph[u].append(v) |
| 82 | + |
| 83 | + return self.topologicalSorting(numCourses, graph) |
49 | 84 | ```
|
50 | 85 |
|
| 86 | +### 思路 1:复杂度分析 |
| 87 | + |
| 88 | +- **时间复杂度**:$O(n + m)$,其中 $n$ 为课程数,$m$ 为先修课程的要求数。 |
| 89 | +- **空间复杂度**:$O(n + m)$。 |
| 90 | + |
0 commit comments