返回

初探 LeetCode 207:巧用拓扑排序算法,叩开课程表之门

前端

课程表问题剖析

课程表问题是一个经典的图论问题,在现实生活中有着广泛的应用。设想你是一名学生,需要在本学期选修多门课程。每门课程都有其先修课程,即必须在学习该课程之前先完成这些先修课程。你的任务是安排一个合理的课程表,使你能够在满足先修课程要求的前提下,顺利完成所有课程。

拓扑排序算法简介

拓扑排序算法是一种用于处理有向无环图(DAG)的算法。DAG 是一种特殊类型的图,其中不存在任何环路。拓扑排序算法的目的是将 DAG 中的顶点按一定的顺序排列,使得对于任何一条有向边 (u, v),顶点 u 总是在顶点 v 之前出现。

拓扑排序算法的基本思想是:从 DAG 中找出所有入度为 0 的顶点,即没有其他顶点指向它们的顶点。然后将这些顶点放入一个队列中,并从队列中逐个取出顶点。对于每个取出的顶点,我们将其所有出边指向的顶点的入度减 1。如果某个顶点的入度变为 0,则将其加入队列中。重复这一过程,直到队列为空或 DAG 中的所有顶点都被加入队列为止。

课程表问题的拓扑排序解法

课程表问题可以抽象为一个 DAG,其中顶点代表课程,有向边代表先修课程关系。拓扑排序算法可以帮助我们找到一个合理的课程安排顺序。

具体步骤如下:

  1. 将所有课程顶点放入一个集合中。
  2. 对于每个课程顶点,计算其入度。
  3. 将所有入度为 0 的课程顶点放入一个队列中。
  4. 从队列中逐个取出课程顶点。
  5. 对于每个取出的课程顶点,将其所有出边指向的课程顶点的入度减 1。
  6. 如果某个课程顶点的入度变为 0,则将其加入队列中。
  7. 重复步骤 4 至 6,直到队列为空或所有课程顶点都被加入队列为止。

代码实现

def find_order(num_courses, prerequisites):
  """
  :type num_courses: int
  :type prerequisites: List[List[int]]
  :rtype: List[int]
  """
  # 构建邻接表
  graph = {}
  for u, v in prerequisites:
    if u not in graph:
      graph[u] = []
    graph[u].append(v)

  # 计算每个课程的入度
  in_degree = [0] * num_courses
  for u in graph:
    for v in graph[u]:
      in_degree[v] += 1

  # 将入度为 0 的课程放入队列中
  queue = []
  for i in range(num_courses):
    if in_degree[i] == 0:
      queue.append(i)

  # 拓扑排序
  result = []
  while queue:
    u = queue.pop()
    result.append(u)
    if u in graph:
      for v in graph[u]:
        in_degree[v] -= 1
        if in_degree[v] == 0:
          queue.append(v)

  # 检查是否所有课程都被安排
  if len(result) == num_courses:
    return result
  else:
    return []

结语

在本文中,我们深入探究了 LeetCode 207 课程表的精妙解法,并详细介绍了拓扑排序算法的原理和应用。通过这个案例,我们不仅掌握了一门强大的算法,也锻炼了我们解决复杂问题的思维能力。在未来的编程之旅中,拓扑排序算法将成为我们解决更多问题的有力工具。