返回
细说「力扣 210」:课程表 II,拓扑排序轻松解决
前端
2024-01-07 20:25:41
课程表 II:拓扑排序的经典应用
在「力扣 210」课程表 II 问题中,我们面临一个需要安排课程学习次序的难题。题目给定两个数组:一个数组 numCourses
表示课程数量,另一个数组 prerequisites
课程之间的依赖关系,即 prerequisites[i] = [ai, bi]
表示学习课程 ai
之前必须先学完课程 bi
。我们的任务是找出一种合理的课程安排,使所有课程都能按正确的次序完成。
拓扑排序:化解依赖关系的利器
解决「力扣 210」的关键在于拓扑排序,这是一种用于解决有向无环图(Directed Acyclic Graph,简称 DAG)中节点排序问题的算法。拓扑排序的目的是为 DAG 中的节点建立一个线性序列,使得对于任何一对节点 u
和 v
,如果存在有向边 u → v
,那么在序列中 u
总是排在 v
之前。
拓扑排序的原理和实现
拓扑排序通常采用两种主要方法:
- 基于深度的搜索(DFS): 从一个未访问的节点开始,对图进行DFS。在访问过程中,记录每个节点的「进入时间」和「离开时间」。离开时间早于进入时间的节点可以安全加入拓扑序列。
- 基于广度的搜索(BDS): 从所有入度为 0 的节点开始,对图进行 BDS。当访问一个节点时,其所有出边指向的节点入度减 1。当一个节点入度变为 0 时,它可以加入拓扑序列。
解决「力扣 210」的拓扑排序实现
基于「力扣 210」中给定的两个数组,我们使用一种基于深度的搜索方法来实现拓扑排序:
from collections import defaultdict,deque
def topological_sort(numCourses, prerequisites):
# 初始化邻接表和入度表
in_degree = [0] * numCourses
graph = defaultdict(list)
for pair in prerequisites:
graph[pair[1]].append(pair[0])
in_degree[pair[0]] += 1
# 使用DFS进行拓扑排序
stack = []
visited = [False] * numCourses
def dfs(node):
visited[node] = True
for neighbor in graph[node]:
if not visited[neighbor]:
dfs(neighbor)
stack.append(node)
for i in range(numCourses):
if not visited[i]:
dfs(i)
return stack[::-1]
代码详解
- 我们首先初始化一个邻接表
graph
来存储课程之间的依赖关系,以及一个入度表in_degree
来记录每个课程的入度(即其他课程对其的依赖数量)。 - 然后,我们使用一个基于深度的搜索函数
dfs
来对图进行拓扑排序。该函数通过使用一个栈stack
来收集已访问的课程,从而生成拓扑序列。 - 在
dfs
函数中,我们首先将当前课程node
访问状态设为已访问。然后,我们访问该课程的出边所指向的每个邻接课程neighbor
,并对其执行拓扑排序。 - 最后,当我们访问完所有课程后,栈
stack
中的课程按拓扑次序排列,可以安全输出。
总结
通过使用拓扑排序算法,「力扣 210」课程表 II 问题可以得到高效且优雅的解决。拓扑排序为我们提供了一种有条理的方式来处理依赖关系问题,在软件工程、任务调度和其他领域有着重要的应用。