首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有效地生成长度N列表中长度K的循环移位的所有排列

有效地生成长度N列表中长度K的循环移位的所有排列
EN

Stack Overflow用户
提问于 2015-10-05 16:39:33
回答 1查看 1.9K关注 0票数 1

如何在长度n的列表中生成长度k的循环移位的所有排列。这里的移位是循环的和正确的。请注意:

如果是K==1,就没有班次。因此,这0位移没有排列。

如果是K==2,这相当于交换元素。因此,所有的n!可以产生排列。

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

代码语言:javascript
复制
P1: [1,4,2] #Original list. No shift.
P2: [4,1,2] #Shift from 0 of [1,4,2]
P3: [4,2,1] #Shift from 1 of [4,1,2] as 0 gives P1
P4: [2,4,1] #Shift from 0 of [4,2,1]  
P5: [2,1,4] #Shift from 1 of [1,4,2] as 0 of P4=P3
P6: [1,2,4] #Shift from 0 of [2,1,4]

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

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

代码语言:javascript
复制
P1 : [1,3,4,2] #Original list. No shift. 
P2 : [4,1,3,2] #Shift from 0th of [1,3,4,2]  
P3 : [3,4,1,2] #Shift from 0th of [4,1,3,2]  
P4 : [3,2,4,1] #Shift from 1th of [3,4,1,2] as 0th gives P1
P5 : [4,3,2,1] #Shift from 0th of [3,2,4,1] 
P6 : [2,4,3,1] #Shift from 0th of [4,3,2,1] 
P7 : [2,1,4,3] #Shift from 1th of [2,4,3,1] as 0th gives P3
P8 : [4,2,1,3] #Shift from 0th of [2,1,4,3] 
P9 : [1,4,2,3] #Shift from 0th of [4,2,1,3] 
P10: [2,3,1,4] #Shift from 1th of [2,1,4,3] as 0 from P9=P7,1 from P9=P1,1 from P8=P5  
P11: [1,2,3,4] #Shift from 0th of [2,3,1,4] 
P12: [3,1,2,4] #Shift from 0th of [1,2,3,4] 

#Now,all have been generated, as moving further will lead to previously found values.

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

代码语言:javascript
复制
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,[])

这将产生输出。

代码语言:javascript
复制
[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

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-10-05 21:10:06

支票

代码语言:javascript
复制
if P in stored_perms:

随着stored_perms的增长,速度会越来越慢,因为它需要一次一个地将Pstored_perms元素进行比较,直到找到副本或遇到列表的末尾。由于每个置换都将被添加到stored_perms中一次,所以与P的比较数在所发现的排列数中至少是二次的,这通常是所有可能的排列或其中的一半,这取决于k是偶数还是奇数(假设1

使用设置要有效得多。Python的集合基于哈希表,因此成员资格检查通常是O(1)而不是O(N)。然而,也有一些限制:

  1. 添加到集合中的元素必须是哈斯德,而Python是不可接受的。幸运的是,元组是可理解的,所以一个小小的改变就可以解决这个问题。
  2. 迭代一个集合是不可预测的。特别是,在迭代集合时,不能可靠地修改它。

除了将P改为元组和将stored_perms更改为集合之外,还需要考虑基于工作队列的搜索,而不是递归搜索。我不知道它是否会更快,但它避免了递归深度的任何问题。

把所有这些放在一起,我把下面的东西组合在一起:

代码语言:javascript
复制
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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32953585

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档