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时就到达了我们递归的边界条件,我们先输出此时的整个列表,再输出交换这两个元素次序后的整个列表,然后记得把这两个元素换回来

我们可以发现 这种写法不只是针对一个按自然数排列的序列进来我给你它的全排列(按次序的字典序),你进来的元素是什么,我都能给你排好,也因此我们可以考虑到如果利用自然数的某些性质则必然可以简化程序

在这里注意以下几个要点:

  1. 我们可以理解问一个大问题=从大问题所处理列表的所有元素中依次取一个元素固定在该大问题所处理列表的第一位且其他元素按原序成为一个子问题的所处理列表
  2. 我们的递归函数叫full_permutation(pending_list, pending_len),为什么一定要有一个pending_len呢,我们不能只传给子函数一个所谓的pending_list的子片段然后当做pending_list,然后len一下得到长度吗,很遗憾,就是不行。因为python语言里的变量和c中的不同,之前的博客说过,python的变量相当于一个标签绑定在实际的值上面,你以为你传了一个列表的片段进去是在修改这个列表本身吗,不是的,你只是告诉了子函数你的pending_list这个列表里的这些标签要绑定在哪些实际值上,当然也有一些其他的方法可以解决这种问题,比如你返回一个什么值再赋值回去。我们这里不做展开。所以这里一直都在处理同一段(至少看起来是同样的一整段)列表,然后用pending_len来表示尾部待处理的长度是方便的(至少在思维上,效率上不一定
  3. 还有个小坑就是你要如何依次地抽取一个元素固定呢,千万别直接和小待处理列表的第一个元素直接交换,打个比方, 1 3 2 4 要把3放第一位一定是3 1 2 4而不是3 2 1 4

其他的读者自行参考代码理解即可 感谢阅读

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)