针对数字序列[1, 2, 3, 4, 5], 常见的排列组合情况有:
1. 求n个数的全排列,要求各个排列升序.[1,2,3,4,5] ... [5,4,3,2,1]
2. 求A(m, n),结果为升序. [1,2,3] .... [5,4,3]
3. 求组合C(m, n), 结果为升序.[1,2,3] ... [3,4,5]
4. 求{1, 2, 3, 4, 5, 6}的所有子集.
方法:
使用递归法:
针对求全排列,可以通过递归求全排列,但是结果不是升序。
针对求子集,递归地取/或不取某元素,结果也不是长序。
使用二进制法:
对0-2^m-1,每个数字对应一个子集。
使用字典序法:
针对全排列,使用next_permutation(),即一个排列,从最后一个元素向前,找到升序的元素,将其与后面比其稍大的元素交换,并将其后的子串逆序,即找到了下一个排列。
针对组合,使用下标增长的方法。初始下标为[0, 1, 2],其下一个下标则为[0, 1, 3], ..., [0, 1, 4], [0, 2, 3], ....[2, 3, 4].
针对A(5, 3),可以使用改进的next_permutation()方法,将next_permutation的"从最后一个元素向前"改为从第3个元素向前来处理。
这两天刚关注了python,就用它来写个小程序吧。
下面是用 python 写的 A(n, m) 的算法:
#!/usr/bin/python
# filename: permutation.py
def permutation(n, m):
global l
ret = 0
while ret == 0:
print( l[0:m] )
ret = next_permutation(m)
# raw_input('###')
def next_permutation(m):
global l
n = len(l)
# print( 'n:', n )
change_indx = -1;
exchange_indx = -1;
for i in range(m-1, -1, -1):
if change_indx > 0:
break
min_value = n+1;
for j in range(i+1, n):
if l[j] > l[i] and l[j]<min_value:
change_indx = i;
exchange_indx = j
min_value = l[j]
if change_indx < 0:
print (' no change_indx. ')
return -1
# print( 'change_indx:', change_indx, exchange_indx, change_indx )
bigger_indx = exchange_indx
tmp = l[change_indx]
l[change_indx] = l[bigger_indx]
l[bigger_indx] = tmp
pre_l = l[0:change_indx+1]
end_l = l[change_indx+1:len(l)]
end_l.sort()
l = pre_l + end_l
# print('pre_l:', pre_l)
# print('end_l:', end_l)
return 0
if __name__ == '__main__':
print ( __name__ )
l = [1, 2, 3, 4, 5]
permutation(len(l), 3)
运行结果如下