思路
这是一个典型的拓扑排序题目, 对拓扑排序不熟悉的,可以看下这个文章 - 揭开「拓扑排序」的神秘面纱,可以说讲的非常详细了。
Ok,我们回到这道题。以题目例2来说:
由于题目本身课程的依赖关系是这么给我们的:[[1,0],[2,0],[3,1],[3,2]]
这种数据格式我们不方便直接使用, 因此我们将其改造成图的一种表示方式邻接矩阵
。
![](https://i-blog.csdnimg.cn/blog_migrate/232285a7982a864a2c1ae97c2b5511c5.png)
可以看到我们浪费了很多空间,这就是邻接矩阵的坏处, 而实际上对于这道题来说,没有必要真的搞一个邻接矩阵,比如这样就行了:
![](https://i-blog.csdnimg.cn/blog_migrate/904235a86a624db20adfc8e8078643bb.png)
可以看出空间复杂度要更好一点。
构建矩阵的过程代码:
adjacent = [[] for _ in range(numCourses)]
for cur, pre in prerequisites:
adjacent[cur].append(pre)
接下来是算法的重点,我们对每一个课程进行一次深度遍历, 并且用visited数组记录每一个课程的访问状态,这样我们可以判断有没有环的存在,如果有环则返回[]
。
而对于visited,我们使用三色标记法
,即没有访问的,访问过但是没有访问完毕的以及完全访问完毕的标记不同颜色。在这里我用0表示没有访问过,1表示访问过但是没有访问完毕,2访问完毕。
DFS 核心逻辑:
def dfs(i):
# 访问过,还没访问完又回来了,说明有环
if visited[i] == 1:
return False
# 已经完全访问完毕,说明行得通
if visited[i] == 2:
return True
# 遍历前标记1
visited[i] = 1
for j in adjacent[i]:
if not dfs(j):
return False
# 遍历后标记2
visited[i] = 2
# 为2的都可以加入res了
res.append(i)
return True
关键点
拓扑排序
三色标记
代码
class Solution:
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
res = []
visited = [0] * numCourses
adjacent = [[] for _ in range(numCourses)]
def dfs(i):
if visited[i] == 1:
return False
if visited[i