207. Course Schedule
Approach I** 广度优先搜索
使用长度的数组记录每个节点的入度,依次将入度为
的节点入队;图的存储使用邻接表**。
class Solution:def canFinish(self, n: int, requisites: List[List[int]]) -> bool:indegrees = [0] * n # 入度adjacency = [[] for _ in range(n)] # 或者直接使用 collections.defaultdict(list)for cur, pre in requisites:indegrees[cur] += 1adjacency[pre].append(cur)queue = collections.deque() # 可用一行'列表生成式'直接建立入度为0的队列for i, indegree in enumerate(indegrees):if indegree == 0:queue.append(i)while queue:pre = queue.popleft()n -= 1for cur in adjacency[pre]:indegrees[cur] -= 1if indegrees[cur] == 0:queue.append(cur)return n == 0
- 时间复杂度:
,需要访问所有节点和所有临边
- 空间复杂度:
,邻接表有
个节点,
条边;队列空间最长为
Approach II** 深度优先搜索**
使用states记录每个节点的搜索状态:
,还未被访问;
,被当前节点出发的dfs访问;
,已经被其他节点出发的dfs访问。 ```python from collections import defaultdict
class Solution: def canFinish(self, n: int, requisites: List[List[int]]) -> bool: def dfs(i): if states[i] == 1: # 被当前节点出发的路径’重复’访问,存在环 return False if states[i] == -1: return True
states[i] = 1for j in edges[i]:if not dfs(j):return Falsestates[i] = -1return Truestates = [0] * n # 0:未访问,1: 被当前节点访问,-1:已被其他节点访问edges = defaultdict(list) # 邻接表for cur, pre in requisites:edges[pre].append(cur)for i in range(n):if not dfs(i):return Falsereturn True
- 时间复杂度:,需要访问所有**节点**和所有**临边**
- 空间复杂度:,邻接表有个**节点**,条**边**;**递归栈**空间最深为
<a name="iBDRJ"></a>
#### [210. Course Schedule II](https://leetcode-cn.com/problems/course-schedule-ii/)
```python
class Solution:
def findOrder(self, N: int, requisites: List[List[int]]) -> List[int]:
res = []
edges = collections.defaultdict(list)
indegrees = [0] * N
for cur, pre in requisites:
indegrees[cur] += 1
edges[pre].append(cur)
# 存放入度为0的节点
queue = collections.deque([i for i in range(N) if indegrees[i] == 0])
while queue:
pre = queue.popleft()
res.append(pre)
for cur in edges[pre]:
indegrees[cur] -= 1
if indegrees[cur] == 0:
queue.append(cur)
if len(res) != N:
return []
return res
- 时间复杂度:
,需要访问所有节点和所有临边
- 空间复杂度:
,邻接表有
个节点,
条边;队列空间最长为
