Python 有效地生成长度为N的列表中长度为K的循环移位的所有置换
如何在长度为n的列表中生成长度为k的循环移位的所有置换。这里的移位是循环的,是右移位。请注意: 如果K==1,则不存在移位。因此,这0个移位没有排列。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)。 为了实现这个算法,我目前正在使用回溯。以下是我
如果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是偶数还是奇数(假设1def 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)