如何生成列表的所有排列?例如:
permutations([])
[]
permutations([1])
[1]
permutations([1, 2])
[1, 2]
[2, 1]
permutations([1, 2, 3])
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
如何生成列表的所有排列?例如:
permutations([])
[]
permutations([1])
[1]
permutations([1, 2])
[1, 2]
[2, 1]
permutations([1, 2, 3])
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
当前回答
功能性风格
def addperm(x,l):
return [ l[0:i] + [x] + l[i:] for i in range(len(l)+1) ]
def perm(l):
if len(l) == 0:
return [[]]
return [x for y in perm(l[1:]) for x in addperm(l[0],y) ]
print perm([ i for i in range(3)])
结果:
[[0, 1, 2], [1, 0, 2], [1, 2, 0], [0, 2, 1], [2, 0, 1], [2, 1, 0]]
其他回答
注意,该算法具有n个阶乘时间复杂度,其中n是输入列表的长度
打印跑步结果:
global result
result = []
def permutation(li):
if li == [] or li == None:
return
if len(li) == 1:
result.append(li[0])
print result
result.pop()
return
for i in range(0,len(li)):
result.append(li[i])
permutation(li[:i] + li[i+1:])
result.pop()
例子:
permutation([1,2,3])
输出:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
如果有人喜欢这个丑陋的单行线(虽然只适用于字符串):
def p(a):
return a if len(a) == 1 else [[a[i], *j] for i in range(len(a)) for j in p(a[:i] + a[i + 1:])]
这是初始排序后生成排列的渐近最优方式O(n*n!)。
有n个!最多进行一次置换,且具有下一次置换(..),以O(n)时间复杂度运行
在3个步骤中,
找到最大的j,使a[j]可以增加以最小可行量增加a[j]找到扩展新a[0..j]的字典最少方法
'''
Lexicographic permutation generation
consider example array state of [1,5,6,4,3,2] for sorted [1,2,3,4,5,6]
after 56432(treat as number) ->nothing larger than 6432(using 6,4,3,2) beginning with 5
so 6 is next larger and 2345(least using numbers other than 6)
so [1, 6,2,3,4,5]
'''
def hasNextPermutation(array, len):
' Base Condition '
if(len ==1):
return False
'''
Set j = last-2 and find first j such that a[j] < a[j+1]
If no such j(j==-1) then we have visited all permutations
after this step a[j+1]>=..>=a[len-1] and a[j]<a[j+1]
a[j]=5 or j=1, 6>5>4>3>2
'''
j = len -2
while (j >= 0 and array[j] >= array[j + 1]):
j= j-1
if(j==-1):
return False
# print(f"After step 2 for j {j} {array}")
'''
decrease l (from n-1 to j) repeatedly until a[j]<a[l]
Then swap a[j], a[l]
a[l] is the smallest element > a[j] that can follow a[l]...a[j-1] in permutation
before swap we have a[j+1]>=..>=a[l-1]>=a[l]>a[j]>=a[l+1]>=..>=a[len-1]
after swap -> a[j+1]>=..>=a[l-1]>=a[j]>a[l]>=a[l+1]>=..>=a[len-1]
a[l]=6 or l=2, j=1 just before swap [1, 5, 6, 4, 3, 2]
after swap [1, 6, 5, 4, 3, 2] a[l]=5, a[j]=6
'''
l = len -1
while(array[j] >= array[l]):
l = l-1
# print(f"After step 3 for l={l}, j={j} before swap {array}")
array[j], array[l] = array[l], array[j]
# print(f"After step 3 for l={l} j={j} after swap {array}")
'''
Reverse a[j+1...len-1](both inclusive)
after reversing [1, 6, 2, 3, 4, 5]
'''
array[j+1:len] = reversed(array[j+1:len])
# print(f"After step 4 reversing {array}")
return True
array = [1,2,4,4,5]
array.sort()
len = len(array)
count =1
print(array)
'''
The algorithm visits every permutation in lexicographic order
generating one by one
'''
while(hasNextPermutation(array, len)):
print(array)
count = count +1
# The number of permutations will be n! if no duplicates are present, else less than that
# [1,4,3,3,2] -> 5!/2!=60
print(f"Number of permutations: {count}")
def permutate(l):
for i, x in enumerate(l):
for y in l[i + 1:]:
yield x, y
if __name__ == '__main__':
print(list(permutate(list('abcd'))))
print(list(permutate([1, 2, 3, 4])))
#[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
#[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
该算法是最有效的算法,它避免了递归调用中的数组传递和操作,适用于Python 2、3:
def permute(items):
length = len(items)
def inner(ix=[]):
do_yield = len(ix) == length - 1
for i in range(0, length):
if i in ix: #avoid duplicates
continue
if do_yield:
yield tuple([items[y] for y in ix + [i]])
else:
for p in inner(ix + [i]):
yield p
return inner()
用法:
for p in permute((1,2,3)):
print(p)
(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)