Kata: 从随机的三字符列表组中恢复秘密字符串

题目:从给定字符串中随机出的三字符列表的集合中,恢复原始字符串,并且三字符列表按字符在字符串中出现顺序排列。作为简化,假设秘密字符串中不会有重复字母。如下:

secret = "whatisup"
triplets = [
    ['t', 'u', 'p'],
    ['w', 'h', 'i'],
    ['t', 's', 'u'],
    ['a', 't', 's'],
    ['h', 'a', 'p'],
    ['t', 'i', 's'],
    ['w', 'h', 's']
]

我想了许久,有这么一个思路:

  1. 分别提取集合triplets中列表第一、第二和第三项组成集合。
  2. 字符串中第一个字母只会在第一集合中出现,排除得出第一个字母。
  3. 从原始集合triplets中去掉找出的第一个字母,并在除去字母的该行末尾添加0,以保持三元素列表。
  4. 重复上述动作,直到triplets变成只包含0。

按上述思路,确实能够写出答案,但结果无比丑陋:

    def recoverSecret(triplets):
        res = []
        while triplets:
            t = list(zip(*triplets))
            big = list(set(t[0]) - set(t[1] + t[2]))
            if not big:
                break
            res.extend(big)
            for item in triplets:
                if big[0] == item[0]:
                    item.pop(0)
                    item.append(0)
        return ''.join(res)

感觉要瞎了。看了下大神的代码,思路是这样的:

  1. 根据triplets生成原字符串的字符列表t,无重复,但非按顺序。
  2. 循环遍历triplets,每次循环按三字符列表中的顺序调整上一步的t中字符顺序。

结果如下:

    def recoverSecret(triplets):
      r = list({i for t in triplets for i in t})
      for t in triplets:
        fix(r, t[1], t[2])
        fix(r, t[0], t[1])
      return ''.join(r)
      
    def fix(t, a, b):
       if t.index(a) > t.index(b):
           t.remove(a)
           t.insert(t.index(b), a)

但上面的算法有问题,比如下面这个例子:

triplets = [
    ['w', 'h', 'p'],
    ['t', 'u', 'p'],
    ['w', 'h', 't'],
    ['t', 's', 'u'],
    ['a', 't', 's'],
    ['h', 'a', 'p'],
    ['t', 'i', 's']
]

当我确定了w, h两个的位置后,又要确认h, a的位置,此时a在h前面,所以把h的位置前提,但因为初始a在w前面,那h就位置放错了,后面又不再有w, h的位置调整,最后的结果当然是错的。

当然,解决方式也很简单,多循环一遍triplets:

for t in triplets * 2

以我的智商暂时就只能想到这里,如有更好的方法,请不吝赐教。

    原文作者:对影yu
    原文地址: https://segmentfault.com/a/1190000011662619
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞