返回
搭建高效的月度刷题计划:深度解析拓扑排序的构造题!
后端
2024-02-17 00:47:48
月度刷题计划:拓扑排序的构造题解析
拓扑排序是一种将有向无环图(DAG)中的顶点排序的方法,使得对于图中的每条有向边 u -> v,顶点 u 总是在顶点 v 之前出现。拓扑排序在许多实际问题中都有应用,如项目管理、任务调度等。
本月刷题计划将以拓扑排序的构造题为重点,通过一系列精心挑选的题目,帮助读者深入理解拓扑排序的原理和应用。
题目
这是 LeetCode 上的 剑指 Offer II 115. 重建序列,难度为 中等。
给定一个长度为 n 的整数数组 nums,数组中每个元素表示一个项目,且项目编号从 1 到 n。我们想知道是否可以将这些项目按照如下规则排序:
- 对于每个项目 i,其直接先决条件(即依赖的项目)是 nums[i] - 1。
- 项目 1 没有先决条件。
如果可以对项目进行排序,请输出排序后的项目编号序列。否则,输出 -1。
示例
输入:nums = [1,2,3,4,0]
输出:[0,1,2,3,4]
解释:项目 0 是项目 1、2、3 和 4 的直接先决条件。
解题思路
拓扑排序是一种有效的算法,可以用于解决此类构造题。以下是以拓扑排序解决该问题的步骤:
- 将所有项目编号作为图中的顶点。
- 对于每个项目 i,将其直接先决条件 nums[i] - 1 作为指向顶点 i 的有向边。
- 使用拓扑排序算法对图进行排序。
- 如果拓扑排序成功,则输出排序后的项目编号序列。否则,输出 -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),用于存储图和入度信息。
总结
通过本月刷题计划,读者将掌握拓扑排序的原理和应用,并能够解决各种拓扑排序的构造题。拓扑排序是一种重要的算法,在图论和计算机科学中都有着广泛的应用。