Description 一般把1-n这n个整数按某个顺序摆放的结果称为这n个整数的一个排列,而全排列指这n个整数能形成的所有排列。例如对1、2、3这三个整数来说,(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1)就是1-3的全排列。现在需要实现按字典序从小到大的顺序输出1~n的全排列,其中(a1,a2,…,an)的字典序小于(b1,b2,…,bn)是指存在一个i,使得a1=b1,a2=b2,…ai-1=bi-1,ai<bi成立。
Input 一个整数n。
Output 按字典序从小到大的顺序输出1~n的全排列,注意输出的格式。
Sample Input 1
3 Sample Output 1
[1, 2, 3] [1, 3, 2] [2, 1, 3] [2, 3, 1] [3, 1, 2] [3, 2, 1]
分析第一次更新 这是笔者想出的第一种写法,效率不高,在递归的同时还有两层循环,复杂度爆表...然而还是简单讲下这种做法的原理和细节,至于优化问题留待下一次的更新。
核心思想:
以[1 2 3 4]为例,我们先固定一个1,然后对[2 3 4]进行排序,而对于[2 3 4],我们先固定一个2,再对[3 4]进行排序,而了当待处理的列表长度为2时就到达了我们递归的边界条件,我们先输出此时的整个列表,再输出交换这两个元素次序后的整个列表,然后记得把这两个元素换回来
我们可以发现 这种写法不只是针对一个按自然数排列的序列进来我给你它的全排列(按次序的字典序),你进来的元素是什么,我都能给你排好,也因此我们可以考虑到如果利用自然数的某些性质则必然可以简化程序
在这里注意以下几个要点:
其他的读者自行参考代码理解即可 感谢阅读
Coding
def full_permutation(pending_list, pending_len):
if pending_len < 2:
print(pending_list)
return
if pending_len == 2:
print(pending_list)
pending_list[-1], pending_list[-2] = pending_list[-2], pending_list[-1]
print(pending_list)
pending_list[-1], pending_list[-2] = pending_list[-2], pending_list[-1]
return
for i in range(len(pending_list) - pending_len, len(pending_list)):
for j in range(i, len(pending_list) - pending_len, -1):
pending_list[j], pending_list[j - 1] = pending_list[j - 1], pending_list[j]
full_permutation(pending_list, pending_len - 1)
for j in range(len(pending_list) - pending_len, i):
pending_list[j], pending_list[j + 1] = pending_list[j + 1], pending_list[j]
return
n = int(input())
full_permutation([i for i in range(1, n + 1)], n)