# # Recover a secret string from random triplets
# # https://www.codewars.com/kata/53f40dff5f9d31b813000774/train/python#我的解法(室友教的)
# Completed in 1.34ms
#使用拓扑排序算法,拓扑排序算法是一种对有向无环图进行排序的算法
#拓扑排序算法的步骤如下:
#1.从有向图中选择一个没有前驱的顶点并输出
#2.从有向图中删除该顶点和所有以它为起点的边
#3.重复1和2直到所有顶点都被输出
#如果有向图中有环,则无法进行拓扑排序
from collections import defaultdict
import queue
def recover_secret(triplets):in_degree = defaultdict(int)end_map = defaultdict(list)for [a,b,c] in triplets:in_degree[a]+=0in_degree[b]+=1in_degree[c]+=1end_map[a].append(b)end_map[b].append(c)zero_in_degree = queue.Queue()for key in in_degree.keys():if in_degree[key]==0:zero_in_degree.put(key)res = ''while(zero_in_degree.qsize()):char = zero_in_degree.get()res+=charfor end in end_map[char]:in_degree[end]-=1if in_degree[end]==0:zero_in_degree.put(end)if(len(res)!=len(in_degree)):return 'error'return restriplets = [['t', 'u', 'p'], ['w', 'h', 'i'], ['t', 's', 'u'], ['a', 't', 's'], ['h', 'a', 'p'], ['t', 'i', 's']
]
print(recover_secret(triplets))# 别人的解法 1
# Completed in 2.71ms
def recover_secret(triplets):# 将所有的字母提取出来,存放到letters中# 不停地遍历triplets,每遍历一个triplet,保证letters中这三个字母的相对顺序是正确的# 直到一次遍历triplets后,letters中的顺序没有发生变化,则说明letters中的字母顺序已符合tripletsletters = list(set([l for triplet in triplets for l in triplet]))# letters = list(set([l for l in triplet for triplet in triplets ])) #这样不行,会显示triplet未定义,说明是从左往右执行的isChanged = Truewhile isChanged:isChanged = Falsefor [a,b,c] in triplets:indexs = [letters.index(a),letters.index(b),letters.index(c)]if not (indexs[0]<indexs[1] and indexs[1]<indexs[2]):indexs.sort()letters[indexs[0]],letters[indexs[1]],letters[indexs[2]] = a,b,cisChanged = Truereturn ''.join(letters)# 别人的解法 2
# Completed in 7.55ms
def recoverSecret(triplets):#letters保存所有字符letters = set(x for triplet in triplets for x in triplet)# map each character to a value in the final ordering# initially, all characters are at 0positions = {char:0 for char in letters}# map each letter to a tuple of sets, one for all# letters to the left and one for all to the right of it# partition 分割,隔墙partitions = {char:(set(),set()) for char in letters}for tri in triplets:a,b,c = tri# add b,c to right of apartitions[a][1].add(b)partitions[a][1].add(c)# add a,c to left/right of bpartitions[b][0].add(a)partitions[b][1].add(c)# add a,b to left of cpartitions[c][0].add(a)partitions[c][0].add(b)# recursively(递归地) decrement(减少) a character's position, # and the position of all characters to its leftdef move_left(char, seen):# 避免重复减少if char in seen:returnpositions[char] -= 1seen.add(char)for l_char in partitions[char][0]:move_left(l_char, seen)# recursively increment a character's position, # and the position of all characters to its rightdef move_right(char, seen):if char in seen:returnpositions[char] += 1seen.add(char)for r in partitions[char][1]:move_right(r, seen)# Perform the infamous "STAND ASIDE" algorithm:# Every character pushes its left/right neighbours# away from itself, with VEHEMENCE and PREJUDICE.# There's some repetition here, but we can afford to# be lazy because the author was lazy and didn't implement# random tests. We could have hard-coded this stuff, but# the STAND-ASIDE algorithm is more glorious.for left, right in partitions.values():for l in left:move_left(l, set())for r in right:move_right(r, set())# sort by position and concatenate the resultreturn "".join(sorted(positions, key=lambda x: positions[x]))triplets = [['t', 'u', 'p'], ['w', 'h', 'i'], ['t', 's', 'u'], ['a', 't', 's'], ['h', 'a', 'p'], ['t', 'i', 's']
]
print(recoverSecret(triplets))# 失败的尝试# collections是python标准库中的一个模块,提供了几种额外的数据结构
# defaultdict是collections模块中的一个类,它是dict的子类,提供了一个工厂函数,为字典提供了默认值
# defaultdict在访问一个不存在的key时,不会抛出KeyError,而是自动为这个key创建一个默认值
# from collections import defaultdict
# def recover_secret(triplets):
# values_map = defaultdict(int)
# for [a,b,c] in triplets:
# values_map[a] += 1
# values_map[b] += 2
# values_map[c] += 3
# sorted_chars = sorted(values_map.keys(), key=lambda x: values_map[x])
# return ''.join(sorted_chars)
# triplets = [
# ['t', 'u', 'p'],
# ['w', 'h', 'i'],
# ['t', 's', 'u'],
# ['a', 't', 's'],
# ['h', 'a', 'p'],
# ['t', 'i', 's']
# ]
# # t<u<p
# # [t<u<p w<h<i]
# # [t<[u<p s] w<h<i]
# # [t<s<u<p w<h<i]
# # [a<t<s<u<p w<h<i]
# # w<h<[a<t<s<u<p i]
# # w<h<a<t<[s<u<p i]
# # w<h<a<t<i<s<u<p# print(recover_secret(triplets))# from collections import defaultdict
# def recover_secret(triplets):
# weights_map = defaultdict(set)
# def upgrade(a,b):
# for ch in weights_map[a]:
# weights_map[b]|=weights_map[ch]
# for [a,b,c] in triplets:
# weights_map[a]|={a}
# weights_map[b]|={b}
# upgrade(a,b)
# weights_map[c]|={c}
# upgrade(b,c)
# # enumerate() 允许在遍历课迭代对象时,同时获取元素的索引盒值,
# # 该函数返回包含索引盒值的元组
# # for i, c in enumerate(triplet):
# # weights_map[c] += 3**i
# # sorted() 返回一个排序后的列表
# sorted_chars = sorted(weights_map.keys(), key=lambda x: len(weights_map[x]))
# return ''.join(sorted_chars)