一道拓扑排序题

题目回忆,只记得大概:

假设黑板上写了一个较长的序列,你和你的朋友们分别都只看到了一部分,而且有可能记错顺序,那么给几个序列,看是否会有consensus,并给出一个可能的完整序列。举例:
A: 1 2 5 15 8
B: 2 7 8
可能序列为1 2 5 15 7 8

A: 1 4 6
B: 4 1
没有consensus

A: 1 2 3
B: 4 5 6
可能序列为 1 2 3 4 5 6(不止一个,这个例子里有很多个可能的序列)

Clarification:
1. 会有多个序列吗? - 会,可能有三个、四个或者多个
2. 同一个序列里有可能出现相同的数字吗? - 不会
3. 完整序列里可能有相同的数字吗? - 不会

解法:

from collections import defaultdict, deque

def find_possible_sequence(sequences):
    graph = defaultdict(set)
    in_degree = defaultdict(int)
    
    # 构建图
    for seq in sequences:
        for i in range(len(seq)):
            if i == 0: # 后面的序列的第一个元素可能在前面已经出现过,第一次出现时,它的入度为0,后面出现时,直接使用前面的入度
                in_degree[seq[i]] = in_degree.get(seq[i], 0)
            if i < len(seq) - 1: # 依次判断前节点和后节点是否有边,并添加边和入度
                if seq[i+1] not in graph[seq[i]]: # 后节点没有出现过,添加边
                    graph[seq[i]].add(seq[i+1])
                    in_degree[seq[i+1]] = in_degree.get(seq[i+1], 0) + 1 # 后节点的入度加1
    
    # 拓扑排序,先把入度为0的节点放入队列
    zero_in_degree_queue = deque([node for node in in_degree if in_degree[node] == 0])
    topological_sorted_list = []
    
    while zero_in_degree_queue: # 遍历入度为0的节点
        node = zero_in_degree_queue.popleft() # 取出入度为0的节点
        topological_sorted_list.append(node) # 加入拓扑排序结果链表
        
        for adjacent in graph[node]: # 遍历该节点所指向的节点
            in_degree[adjacent] -= 1 # 将所有该节点指向的节点的入度减1,因为该节点被拿走了,所以它指向的节点的入度都要减1
            if in_degree[adjacent] == 0: # 如果该节点指向的节点的入度为0,就把它放入入度为0的队列
                zero_in_degree_queue.append(adjacent)
    
    if len(topological_sorted_list) == len(in_degree): # 判断拓扑排序结果是否正确
        return topological_sorted_list
    else:
        return "没有consensus"

# 示例输入
sequences_list = [
    [[1, 2, 5, 15, 8], [2, 7, 8]],
    [[1, 4, 6], [4, 1]],
    [[1, 2, 3], [4, 5, 6]]
]

# 输出结果
for sequences in sequences_list:
    print(find_possible_sequence(sequences))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值