【问题标题】:Sorting a string in array, making it sparsely populated对数组中的字符串进行排序,使其稀疏
【发布时间】:2010-05-24 12:51:03
【问题描述】:

例如,假设我有这样的字符串:

duck duck duck duck goose goose goose dog 

我希望它尽可能地稀疏,比如在这种情况下

duck goose duck goose dog duck goose duck

您会推荐哪种算法?代码片段或通用指针会很有用,语言欢迎 Python、C++ 和额外的荣誉,如果你有办法在 bash 中做到这一点。

【问题讨论】:

  • 我认为随机化就足够了。不要嘎嘎!
  • 是的,我尝试在 Python 脚本中使用随机化,但事实是,随机化并不能让它尽可能地稀疏,它只是让它有点混乱。所以我会得到随机化的结果就像''鹅鸭鸭鹅鸭狗鸭鹅'
  • 哦!我刚刚得到了鸭子的笑话,哈哈。
  • 明确一点:总是有正确的答案吗? (最多排列具有相同条目数的项目。)或者你想要/允许一些随机性?
  • 那么正确的答案应该是让每个项目尽可能远离它的种类。当我第一次处理这个问题时,我研究了随机性,但它并没有真正做到这一点,我有点意识到它需要尽可能多地排序。

标签: c++ python algorithm bash


【解决方案1】:

我会按重复的数量对数组进行排序,从重复次数最多的元素开始,将这些元素分散到尽可能远的地方

在您的示例中,duck 被复制了 4 次,因此对于从 0 到 3(含)的 n,duck 将被放置在 n*8/4 的位置。

然后将下一个重复次数最多的(鹅)放在 n*8/3 + 1 的位置,因为 n 从 0 到 2 包括在内,如果那里已经放了东西,那就把它放在下一个空的位置。等等等等

【讨论】:

    【解决方案2】:

    我认为大概是这样的:

    L = "duck duck duck duck goose goose goose dog ".split() 
    
    from itertools import cycle, islice, groupby
    
    # from: http://docs.python.org/library/itertools.html#recipes
    def roundrobin(*iterables):
        "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
        # Recipe credited to George Sakkis
        pending = len(iterables)
        nexts = cycle(iter(it).next for it in iterables)
        while pending:
            try:
                for next in nexts:
                    yield next()
            except StopIteration:
                pending -= 1
                nexts = cycle(islice(nexts, pending))
    
    groups = [list(it) for k,it in groupby(sorted(L))]
    
    # some extra print so you get the idea
    print L
    print groups
    print list(roundrobin(*groups))
    

    输出:

    ['dog', 'duck', 'duck', 'duck', 'duck', 'goose', 'goose', 'goose']
    [['dog'], ['duck', 'duck', 'duck', 'duck'], ['goose', 'goose', 'goose']]
    ['dog', 'duck', 'goose', 'duck', 'goose', 'duck', 'goose', 'duck']
    

    所以你想要某种循环:-)


    好吧,循环赛并不完美。

    这是您所想的蛮力(也就是效率极低)版本。

    # this is the function we want to maximize
    def space_sum( L ):
        """ return the sum of all spaces between all elements in L"""
        unique = set(L)
        def space(val):
            """ count how many elements are between two val """
            c = 0
            # start with the first occurrence of val, then count
            for x in L[1+L.index(val):]: 
                if x==val:
                    yield c
                    c = 0
                else:
                    c += 1
        return sum(sum(space(val)) for val in unique)
    
    print max((space_sum(v), v) for v in permutations(L))
    
    # there are tons of equally good solutions
    print sorted(permutations(L), key=space_sum, reverse=True)[:100] 
    

    【讨论】:

    • 循环法很好,尽管一旦它从所有组中进行了选择,它就不会尽可能地稀疏。如果我只是添加更多的实例('duck', 'duck', 'duck', 'duck', 'duck', 'duck', 'goose', 'goose', 'goose', 'goose', 'dog', 'dog'] [['dog', 'dog'], ['duck', 'duck', 'duck', 'duck', 'duck', 'duck'], ['goose', 'goose', 'goose', 'goose']] ['dog', 'duck', 'goose', 'dog', 'duck', 'goose', 'duck', 'goose', 'duck', 'goose', 'duck', 'duck')更容易演示我还没有尝试过暴力方法,我会告诉你它是怎么回事
    • 我刚刚尝试了蛮力方法,排列未定义。
    【解决方案3】:

    实际上如何测量稀疏性?顺便说一句,一个简单的random shuffle 可能会起作用。

    【讨论】:

    • 通过测量稀疏度,我的意思是每个项目的每个实例都尽可能远离字符串中的另一个实例。
    【解决方案4】:

    按数量对您输入的内容进行排序。

    1. 项目类型 1 放置在链表中。 (店铺中间链接)。
    2. 下一个项目类型计数 = c 总当前列表大小 = N。 使用列表中间的“银行家四舍五入”在 c 中分配第 2 项。

    3. 转到 2。

    【讨论】:

      【解决方案5】:

      如果我正确理解了你对“稀疏”的定义,那么这个函数应该正是你想要的:

      # python ≥ 2.5
      import itertools, heapq
      
      def make_sparse(sequence):
          grouped= sorted(sequence)
          item_counts= []
          for item, item_seq in itertools.groupby(grouped):
              count= max(enumerate(item_seq))[0] + 1
              item_counts.append( (-count, item) ) # negative count for heapq purposes
          heapq.heapify(item_counts)
      
          count1, item1= heapq.heappop(item_counts)
          yield item1; count1+= 1
          while True:
              try:
                  count2, item2= heapq.heappop(item_counts)
              except IndexError: # no other item remains
                  break
              yield item2; count2+= 1
              if count1 < 0:
                  heapq.heappush(item_counts, (count1, item1))
              item1, count1= item2, count2
      
          # loop is done, produce remaining item1 items
          while count1 < 0:
              yield item1; count1+= 1
      
      if __name__ == "__main__":
          # initial example
          print list(make_sparse(
              "duck duck duck duck goose goose goose dog".split()))
          # updated example
          print list(make_sparse([
              'duck', 'duck', 'duck', 'duck', 'duck', 'duck',
              'goose', 'goose', 'goose', 'goose', 'dog', 'dog']))
          # now a hard case: item 'a' appears more than:
          # > total_len//2 times if total_len is even
          # > total_len//2+1 times if total_len is odd
          print list(make_sparse("aaaaaabbcc"))
      

      这些示例产生以下输出:

      ['duck', 'goose', 'duck', 'goose', 'duck', 'dog', 'duck', 'goose']
      ['duck', 'goose', 'duck', 'goose', 'duck', 'dog', 'duck', 'goose', 'duck', 'dog', 'duck', 'goose']
      ['a', 'b', 'a', 'c', 'a', 'b', 'a', 'c', 'a', 'a']
      

      一个微妙的提示:在第一个和第二个示例中,反转输出顺序可能看起来更优化。

      【讨论】:

        【解决方案6】:

        上面有很好的答案,关于对最常见的字符串进行最远的排序和分离。但是,如果您有太多数据无法排序或不想花时间,请查看准随机数 (http://mathworld.wolfram.com/QuasirandomSequence.html)。在 Numerical Recipes 书中有一个简单的实现。这些是“看起来”随机的数字,即填充一个空格但尽量避免彼此。它在您想要“随机”采样某些东西的应用程序中被大量使用,但您想要有效地采样整个空间而不是真正的随机。

        【讨论】:

          猜你喜欢
          • 2015-07-07
          • 2015-06-18
          • 2022-10-23
          • 2016-07-18
          • 2011-03-14
          • 1970-01-01
          相关资源
          最近更新 更多