返回

搭建高效的月度刷题计划:深度解析拓扑排序的构造题!

后端

月度刷题计划:拓扑排序的构造题解析

拓扑排序是一种将有向无环图(DAG)中的顶点排序的方法,使得对于图中的每条有向边 u -> v,顶点 u 总是在顶点 v 之前出现。拓扑排序在许多实际问题中都有应用,如项目管理、任务调度等。

本月刷题计划将以拓扑排序的构造题为重点,通过一系列精心挑选的题目,帮助读者深入理解拓扑排序的原理和应用。

题目

这是 LeetCode 上的 剑指 Offer II 115. 重建序列,难度为 中等。

给定一个长度为 n 的整数数组 nums,数组中每个元素表示一个项目,且项目编号从 1 到 n。我们想知道是否可以将这些项目按照如下规则排序:

  1. 对于每个项目 i,其直接先决条件(即依赖的项目)是 nums[i] - 1。
  2. 项目 1 没有先决条件。

如果可以对项目进行排序,请输出排序后的项目编号序列。否则,输出 -1。

示例

输入:nums = [1,2,3,4,0]
输出:[0,1,2,3,4]
解释:项目 0 是项目 1234 的直接先决条件。

解题思路

拓扑排序是一种有效的算法,可以用于解决此类构造题。以下是以拓扑排序解决该问题的步骤:

  1. 将所有项目编号作为图中的顶点。
  2. 对于每个项目 i,将其直接先决条件 nums[i] - 1 作为指向顶点 i 的有向边。
  3. 使用拓扑排序算法对图进行排序。
  4. 如果拓扑排序成功,则输出排序后的项目编号序列。否则,输出 -1。

实现代码

from collections import defaultdict
from queue import Queue

def can_finish(nums):
    """
    判断是否可以对项目进行排序

    Args:
    nums: 项目编号序列

    Returns:
    True 如果可以排序,False 如果不能排序
    """

    # 构造图
    graph = defaultdict(list)
    indegree = [0] * len(nums)
    for i in range(1, len(nums)):
        graph[nums[i] - 1].append(i)
        indegree[i] += 1

    # 拓扑排序
    queue = Queue()
    for i in range(len(nums)):
        if indegree[i] == 0:
            queue.put(i)

    result = []
    while not queue.empty():
        current = queue.get()
        result.append(current)
        for neighbor in graph[current]:
            indegree[neighbor] -= 1
            if indegree[neighbor] == 0:
                queue.put(neighbor)

    return len(result) == len(nums)

def find_order(nums):
    """
    找到项目排序序列

    Args:
    nums: 项目编号序列

    Returns:
    项目排序序列,如果不能排序则返回 -1
    """

    if not can_finish(nums):
        return -1

    # 拓扑排序
    queue = Queue()
    for i in range(len(nums)):
        if indegree[i] == 0:
            queue.put(i)

    result = []
    while not queue.empty():
        current = queue.get()
        result.append(current)
        for neighbor in graph[current]:
            indegree[neighbor] -= 1
            if indegree[neighbor] == 0:
                queue.put(neighbor)

    return result

nums = [1,2,3,4,0]
print(find_order(nums))

复杂度分析

时间复杂度:O(n + m),其中 n 为项目数,m 为项目间的依赖关系数。

空间复杂度:O(n),用于存储图和入度信息。

总结

通过本月刷题计划,读者将掌握拓扑排序的原理和应用,并能够解决各种拓扑排序的构造题。拓扑排序是一种重要的算法,在图论和计算机科学中都有着广泛的应用。