返回

征服 LeetCode 210:课程表 II 的妙招

前端

导语

踏入 LeetCode 210 的殿堂,我们踏上了一段智力探险之旅。课程表 II 问题看似复杂,但只要掌握拓扑排序的真谛,就能轻松驾驭。本文将为你揭开拓扑排序的神秘面纱,助你征服 LeetCode 210 的挑战。

拓扑排序:拨开迷雾见彩虹

拓扑排序是一种算法,它对有向无环图(DAG)进行排序。DAG 中的节点表示任务,而边表示任务之间的依赖关系。拓扑排序的目的是找到任务的执行顺序,确保所有依赖关系都得到满足。

拓扑排序的实现通常采用深度优先搜索(DFS)。DFS 从一个起始节点开始,沿着所有可能的路径探索图,直到访问所有节点。在探索过程中,我们记录每个节点的入度,即指向该节点的边的数量。

算法流程:循序渐进,巧解难题

LeetCode 210 课程表 II 的解决方法如下:

  1. 构建邻接表: 根据给定的先修课程关系,创建邻接表来表示图。
  2. 计算入度: 初始化一个数组,记录每个课程的入度。
  3. 拓扑排序: 使用 DFS 从入度为 0 的课程开始,依次探索图,并更新课程的入度。
  4. 结果输出: 将按拓扑顺序访问的课程输出为最终结果。

实例解析:拨云见日,豁然开朗

考虑以下示例:

numCourses = 4
prerequisites = [[1,0],[2,0],[3,1],[3,2]]

根据给定的先修课程关系,我们可以构建邻接表:

graph = {
    0: [1],
    1: [2],
    2: [3],
    3: []
}

计算每个课程的入度:

indegree = [1, 1, 1, 0]

从入度为 0 的课程 3 开始 DFS:

  • 访问课程 3,并将其从图中删除。
  • 更新其他课程的入度:课程 2 的入度 -1。

重复上述步骤,直到所有课程都被访问:

访问顺序:3 -> 2 -> 1 -> 0

最终结果为:

[3, 2, 1, 0]

循环检测:警惕陷阱,规避风险

在进行拓扑排序时,我们需要警惕循环检测。如果图中存在环,则不存在拓扑顺序。我们可以通过记录 DFS 访问过的节点来检测循环。如果发现某个节点再次被访问,则说明存在环。

代码实现:一览无余,胜券在握

def findOrder(numCourses, prerequisites):
    # 构建邻接表
    graph = {i: [] for i in range(numCourses)}
    for pair in prerequisites:
        graph[pair[1]].append(pair[0])

    # 计算入度
    indegree = [0] * numCourses
    for pair in prerequisites:
        indegree[pair[0]] += 1

    # 拓扑排序
    result = []
    queue = [i for i in range(numCourses) if indegree[i] == 0]
    while queue:
        course = queue.pop(0)
        result.append(course)
        for next_course in graph[course]:
            indegree[next_course] -= 1
            if indegree[next_course] == 0:
                queue.append(next_course)

    # 循环检测
    if len(result) != numCourses:
        return []

    return result

总结

通过拓扑排序,我们可以轻松解决 LeetCode 210 课程表 II 问题。掌握拓扑排序的原理和实现方法,是算法学习中的重要一步。不断探索算法的世界,你会发现编程的魅力无穷。

致谢

感谢您的关注和支持。期待与您继续探索算法的奥秘,共创技术新篇章。