返回

Python轻松搞定LeetCode 207:课程表(DFS+BFS)

后端

前言

在计算机科学中,图论是一个重要的分支,它主要研究图的结构和性质。图论在许多领域都有着广泛的应用,例如网络、通信、交通、社交网络等。在LeetCode上,图论题目也经常出现,考察的内容包括图的遍历、最短路径、最小生成树等。

LeetCode 207:课程表

LeetCode 207:课程表是一道经典的图论算法题,考察图中是否有环的问题。题目如下:

你需要设计一个课程表,使每门课只能在所有依赖它的课程结束后才能开课。请你判断是否能够满足这个要求,并给出课表的顺序。

解题思路

要解决这个问题,我们可以将课程之间的依赖关系表示成一个有向图。然后,我们可以使用DFS或BFS来遍历这个有向图。如果在遍历过程中检测到环,则说明课程表无法满足要求。否则,我们可以根据遍历结果输出课程的顺序。

DFS解法

DFS(Depth-First Search,深度优先搜索)是一种图的遍历算法,它通过沿着一条路径深度搜索,直到无法继续深入时才回溯到前一个节点继续搜索。DFS解法的步骤如下:

  1. 将所有课程初始化为未访问状态。
  2. 选择一个课程作为起点,开始DFS遍历。
  3. 在DFS过程中,如果遇到一个课程已经被访问过,则说明存在环,返回False。
  4. 如果在DFS过程中,所有课程都已经被访问过,则说明不存在环,返回True。
def canFinish_dfs(numCourses, prerequisites):
  """
  :type numCourses: int
  :type prerequisites: List[List[int]]
  :rtype: bool
  """
  # Create an adjacency list representation of the graph.
  adj_list = [[] for _ in range(numCourses)]
  for course, prereq in prerequisites:
    adj_list[prereq].append(course)

  # Initialize the visited and stack arrays.
  visited = [False] * numCourses
  stack = []

  # Perform DFS on each unvisited node.
  for i in range(numCourses):
    if not visited[i]:
      if dfs(i, adj_list, visited, stack):
        return False

  # If there is no cycle, return True.
  return True


def dfs(node, adj_list, visited, stack):
  """
  Perform DFS on the given node.

  :param node: The current node.
  :param adj_list: The adjacency list representation of the graph.
  :param visited: The array of visited nodes.
  :param stack: The stack of nodes that have been visited.
  :return: True if a cycle is detected, False otherwise.
  """
  # Mark the node as visited.
  visited[node] = True

  # Push the node onto the stack.
  stack.append(node)

  # Visit all the neighbors of the node.
  for neighbor in adj_list[node]:
    # If the neighbor has not been visited, perform DFS on it.
    if not visited[neighbor]:
      if dfs(neighbor, adj_list, visited, stack):
        return True
    # If the neighbor is already in the stack, a cycle has been detected.
    elif neighbor in stack:
      return True

  # Pop the node from the stack.
  stack.pop()

  # Return False to indicate that no cycle has been detected.
  return False

BFS解法

BFS(Breadth-First Search,广度优先搜索)也是一种图的遍历算法,它通过一层一层地遍历图中的所有节点,直到将所有节点都访问过。BFS解法的步骤如下:

  1. 将所有课程初始化为未访问状态。
  2. 将所有课程的入度初始化为0。
  3. 将所有入度为0的课程加入队列。
  4. 从队列中取出一个课程,并将其标记为已访问。
  5. 对于该课程的所有邻接课程,将它们的入度减1。
  6. 如果某个邻接课程的入度变为0,则将其加入队列。
  7. 重复步骤4-6,直到队列为空。
def canFinish_bfs(numCourses, prerequisites):
  """
  :type numCourses: int
  :type prerequisites: List[List[int]]
  :rtype: bool
  """
  # Create an adjacency list representation of the graph.
  adj_list = [[] for _ in range(numCourses)]
  for course, prereq in prerequisites:
    adj_list[prereq].append(course)

  # Initialize the in-degree array.
  in_degree = [0] * numCourses
  for course, prereq in prerequisites:
    in_degree[course] += 1

  # Initialize the queue with all courses that have in-degree 0.
  queue = [i for i in range(numCourses) if in_degree[i] == 0]

  # While there are still courses in the queue, process them.
  while queue:
    # Get the first course in the queue.
    course = queue.pop(0)

    # Mark the course as visited.
    in_degree[course] -= 1

    # For each neighbor of the course, decrement its in-degree.
    for neighbor in adj_list[course]:
      in_degree[neighbor] -= 1

      # If a neighbor's in-degree becomes 0, add it to the queue.
      if in_degree[neighbor] == 0:
        queue.append(neighbor)

  # If all courses have been visited, return True.
  return all(in_degree[i] == 0 for i in range(numCourses))

复杂度分析

DFS和BFS解法的复杂度都为O(V+E),其中V是课程的数量,E是依赖关系的数量。

总结

LeetCode 207:课程表是一道经典的图论算法题,考察图中是否有环的问题。我们使用DFS和BFS两种方法来解决这个问题,并提供了详细的Python代码和注释。希望这篇文章对大家有所帮助!