题目回忆,只记得大概:
假设黑板上写了一个较长的序列,你和你的朋友们分别都只看到了一部分,而且有可能记错顺序,那么给几个序列,看是否会有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))