Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 有效地生成长度为N的列表中长度为K的循环移位的所有置换_Python_Algorithm_Permutation_Cyclic - Fatal编程技术网

Python 有效地生成长度为N的列表中长度为K的循环移位的所有置换

Python 有效地生成长度为N的列表中长度为K的循环移位的所有置换,python,algorithm,permutation,cyclic,Python,Algorithm,Permutation,Cyclic,如何在长度为n的列表中生成长度为k的循环移位的所有置换。这里的移位是循环的,是右移位。请注意: 如果K==1,则不存在移位。因此,这0个移位没有排列。 如果K==2,这相当于交换元素。因此都是n!可以生成置换 例如,如果列表是[1 4 2],K=2(因此从0到N-K,循环) 如果K==3,事情会变得有趣,因为忽略了一些排列 例如,如果list=[1,3,4,2],K=3(因此从索引0到4-3,循环) 请注意,这些排列是应该是(24)的一半(12)。 为了实现这个算法,我目前正在使用回溯。以下是我

如何在长度为n的列表中生成长度为k的循环移位的所有置换。这里的移位是循环的,是右移位。请注意:

如果K==1,则不存在移位。因此,这0个移位没有排列。
如果K==2,这相当于交换元素。因此都是n!可以生成置换

例如,如果列表是[1 4 2],K=2(因此从0到N-K,循环)

如果K==3,事情会变得有趣,因为忽略了一些排列

例如,如果list=[1,3,4,2],K=3(因此从索引0到4-3,循环)

请注意,这些排列是应该是(24)的一半(12)。 为了实现这个算法,我目前正在使用回溯。以下是我迄今为止尝试过的(Python)

这将产生输出

这正是我想要的,但是速度要慢得多,因为这里递归深度超过了N>7。我希望我已经解释清楚了。任何人,有任何优化吗

支票

if P in stored_perms:
随着
storaged_perms
的增长,速度越来越慢,因为它需要将
p
storaged_perms
的元素一次比较一个,直到找到副本或遇到列表结尾。由于每个排列将被添加到
存储的_perms
中一次,因此与
P
进行比较的次数至少是发现的排列数的二次方,通常是所有可能的排列或其中的一半,这取决于k是偶数还是奇数(假设1 使用电脑会更有效。Python的集合基于哈希表,因此成员资格检查通常是O(1)而不是O(N)。但是,有几个限制:

  • 添加到集合中的元素必须是可散列的,Python列表不可散列。幸运的是,元组是可散列的,所以一个小小的更改就解决了这个问题

  • 在集合上迭代是不可预测的。特别是,在对集合进行迭代时,无法可靠地修改集合

  • 除了将p更改为元组并将存储的_perms更改为集合之外,还值得考虑基于工作队列而不是递归搜索的搜索。我不知道它是否会更快,但它避免了递归深度的任何问题

    把所有这些放在一起,我把以下几点放在一起:

    def get_cyclics(p, k):
      found = set()      # set of tuples we have seen so far
      todo = [tuple(p)]  # list of tuples we still need to explore
      n = len(p)
      while todo:
        x = todo.pop()
        for i in range(n - k + 1):
          perm = ( x[:i]                    # Prefix
                 + x[i+1:i+k] + x[i:i+1]    # Rotated middle
                 + x[i+k:]                  # Suffix
                 )
          if perm not in found:
            found.add(perm)
            todo.append(perm)
      for x in found:
        print(x)
    

    试着从增加整数开始:1,2,然后是1,2,3,最后是1,2,3,4-用手检查正确答案,然后在结果中寻找模式。我想你是想通过正在进行的CodeChef竞赛来解决这个问题。枚举在这里帮不了你。哈哈,是的,我知道。这是排列的简单奇偶校验,并打印其字典索引/2。我只是热衷于改进我最初的方法,因为我总是从蛮力开始,并在继续的过程中进行优化。谢谢,谢谢你的提示。@AmanGarg:你正在寻找的解决方案是一种决定是否可以生成特定排列的算法。有超过300万个10个元素的排列,而且数量继续呈指数级增长,因此枚举排列绝对不是一条可行之路。这里有一个提示:寻找置换奇偶性。
    def get_possible_cyclic(P,N,K,stored_perms): #P is the original list
        from collections import deque  
    
        if P in stored_perms:
            return    #Backtracking to the previous
    
        stored_perms.append(P)
    
        for start in xrange(N-K+1):
            """
            Shifts cannot wrap around. Eg. 1,2,3,4 ,K=3
            Recur for  (1,2,3),4 or 1,(2,3,4) where () denotes the cycle
            """
            l0=P[:start]                    #Get all elements that are before cycle ranges
            l1=deque(P[start:K+start])      #Get the elements we want in cycle
            l1.rotate()                     #Form their cycle
            l2=P[K+start:]                  #Get all elements after cycle ranges
    
            l=l0+list(l1)+l2                #Form the required list
            get_possible_cyclic(l,N,K,stored_perms)
    
        for index,i in enumerate(stored_perms):    
            print i,index+1
    
    get_possible_cyclic([1,3,4,2],4,3,[])
    get_possible_cyclic([1,4,2],3,2,[])
    
    [1, 3, 4, 2] 1
    [4, 1, 3, 2] 2
    [3, 4, 1, 2] 3
    [3, 2, 4, 1] 4
    [4, 3, 2, 1] 5
    [2, 4, 3, 1] 6
    [2, 1, 4, 3] 7
    [4, 2, 1, 3] 8
    [1, 4, 2, 3] 9
    [2, 3, 1, 4] 10
    [1, 2, 3, 4] 11
    [3, 1 ,2, 4] 12
    
    [1, 4, 2] 1
    [4, 1, 2] 2
    [4, 2, 1] 3
    [2, 4, 1] 4
    [2, 1, 4] 5
    [1, 2, 4] 6
    
    if P in stored_perms:
    
    def get_cyclics(p, k):
      found = set()      # set of tuples we have seen so far
      todo = [tuple(p)]  # list of tuples we still need to explore
      n = len(p)
      while todo:
        x = todo.pop()
        for i in range(n - k + 1):
          perm = ( x[:i]                    # Prefix
                 + x[i+1:i+k] + x[i:i+1]    # Rotated middle
                 + x[i+k:]                  # Suffix
                 )
          if perm not in found:
            found.add(perm)
            todo.append(perm)
      for x in found:
        print(x)