一个超简单的求全排列的算法,Python仅需几行即可实现

前言

组合问题即从 n n 个元素中抽取出 m m 个元素,其中 0 m n 0 \leq m \leq n 。这个问题的算法很多,基本可以分为递规法基于用树的分支法,或计数器法,这些办法虽然可以解决问题,但是大多比较麻烦,代码也比较繁琐。本方设计了一种基于二进制的遍历算法,不仅代码量少实现简单,而且算法高效计算速度快。

实现原理

当有 n n 个元素时,可以看成序列: ( A 1 , A 2 , A 3 , . . . , A n ) (A_1, A_2, A_3, ..., A_n) 的向量,每个向量中的任何一个维度只有 { 0 , 1 } \{0, 1\} 两个值。举例来说,当 n = 8 n=8 时,可以排列成以下的列表。

A1      A2      A3      A4      A5      A6      A7      A8
0       0       0       0       0       0       1       1
0       0       0       0       0       1       0       1

                   ...(省略若干行) ...
                   
1       0       0       1       0       0       0       0
1       0       1       0       0       0       0       0
1       1       0       0       0       0       0       0

每行的0和1的组合,我们可以看成一个八位二进制的值,比如第1行 0 0 0 0 0 0 1 1 可以表示为 3 3 。这样所表示的数据的范围是 [ 0 , 2 8 ) [0, 2^8) ,即 [ 0 , 256 ) [0, 256) 共256个元素,所以我们只要遍历这些值,然后将其转换为二进制即可。用 1 1 表示选中, 0 0 表示未选中。当所有组合遍历实现以后,再计算每一行中 1 1 的个数,从而实现 C n m C_n^m

实现方法

本文先给出实现方法。求全组合问题,其实可以非常简单,如下代码所示,可以以2行代码求出所有的组合。

def permutation(n):
    return [bin(i)[2:].rjust(n,'0') for i in range(2**n)]

如果求组合 C n m C_n^m 几行代码也可以搞定。

def permutation(n, m):
    list = []                 # 用于保存结果
    for i in range(2**n):
        s = '{}'.format(bin(i)[2:].rjust(n,'0'))
        if s.count('1') == m: # 包括 m 个 1,则添加进结果列表
            list.append(s)
    return list

比如,求 C 8 3 C_8^3 ,使用以下测试代码:

r = permutation(8, 2)
print("C(8, 2) = " + str(len(r)) + ", listed as follows")
print('\t'.join(["A" + str(i) for i in range(8)]))
for v in r:
    print('\t'.join(v))       

结果输出如下:

C(8, 2) = 28, listed as follows
A0      A1      A2      A3      A4      A5      A6      A7
0       0       0       0       0       0       1       1
0       0       0       0       0       1       0       1
0       0       0       0       0       1       1       0
0       0       0       0       1       0       0       1
0       0       0       0       1       0       1       0
0       0       0       0       1       1       0       0
0       0       0       1       0       0       0       1
0       0       0       1       0       0       1       0
0       0       0       1       0       1       0       0
0       0       0       1       1       0       0       0
0       0       1       0       0       0       0       1
0       0       1       0       0       0       1       0
0       0       1       0       0       1       0       0
0       0       1       0       1       0       0       0
0       0       1       1       0       0       0       0
0       1       0       0       0       0       0       1
0       1       0       0       0       0       1       0
0       1       0       0       0       1       0       0
0       1       0       0       1       0       0       0
0       1       0       1       0       0       0       0
0       1       1       0       0       0       0       0
1       0       0       0       0       0       0       1
1       0       0       0       0       0       1       0
1       0       0       0       0       1       0       0
1       0       0       0       1       0       0       0
1       0       0       1       0       0       0       0
1       0       1       0       0       0       0       0
1       1       0       0       0       0       0       0

结论

综上,我们只需要利用二进制表示每一种情况,这样只需要 2 n 2^n 种情况全部都可以考虑进来,且不需要任何多余的计算,所以计算效果也特别高。

发布了326 篇原创文章 · 获赞 94 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/weixin_43145361/article/details/104047822
今日推荐