剔除重复_含重复数字的全排列个数

前言

上一篇文章中,我们在求取抽卡片的所有次数时,用到了全排列,当时提到由于总卡片数是35,这个数字产生的全排列过于巨大,计算起来耗时久,因此我们只用10和12两个数字进行示例说明。 事实上,在求全排列的个数时,上一篇文章中编写的程序用的是最容易被同学们理解但却是最暴力的方法,尽管用暴力方法可以将所有方案列写出来,但用该程序来求全排列的个数问题时并不是最优的。 这一篇文章中,我们来研究一下含重复数字的全排列个数求解问题。

不重复数字的全排列

对于求不重复数字的全排列,其实很容易计算,只要学习过高中数学的同学都会,那就是求这个全排列数目的阶乘即可。在Python中,求阶乘有现成的函数:

8599afe66b0db7b8d6a17022cc51066b.png

或者,用scipy中的perm来求一个数的全排列数:

2997bf2bc3635d61557b7575bdad93cd.png

如果自定义求,也是容易的:

0f04abcab684fb8518d6e154d864d374.png

计算含重复数字全排列数思路一 如果给出的数字中有重复的,比如给出1、1、1、2、2、3这6个数,要求由它组成的不同6位数个数,应该如何求取呢? 当6个数字不重复时,我们可以直接求6的阶乘,对于其中重复的数字,需要进行剔除,比如其中的1有三个,2有两个,这就需要将这些情况剔除,数学表示为:

69d81b8f6127ba15c12649682732eb14.png

用程序计算如下:

04dcaae877d163c854a4c0cc92e94899.png

在得到这个函数之后,我们再来看看上篇文章中关于对35张卡片的抽取总方法数有多少种:

da6005959f93723ce639e8802c00196b.png

我们来测试一下利用这种方式计算35张卡片的总抽取次数所花时间:

0b76c55d4529913368bd1f27945522db.png

可以看出,只需要1毫秒多,而如果利用上一篇文章中的方法,计算35张卡片的总抽取次数也许需要几个小时都有可能。 可以用这个函数来验证一下上一篇文章中提到的当卡片为10和12时的总次数是否一致:

a4211f96d6904bd7cfc797cf80176bbc.png

从结果输出来看,是与上一篇文章中的数字相符合的。

计算含重复数字全排列数思路二

另一种计算含重复数字的全排列数算法是分步法,同样以1、1、1、2、2、3这6个数为例来说明。 为了组成六位数,可考虑逐步从这六个数字中选取,首先我们将三个1选取出来,这三个1在六位数中可能出现位置的情况是求在6个数中选3个的组合(同学们思考下为什么不是排列?),其次再将两个2选取出来,在6位数中余下的三个位置上安排这两个2,即求在3个位置中选取2个位置的组合(理由同上),最后来安排一个3,这样计算的结果可由下式表示:

6dadf53d12b2eec4db188d6f26829fb0.png

计算可得: 60。 这与第一种方法计算结果一致,采用这个计算公式,我们来看35张卡片用程序计算的代码演示是怎样的:

60011d743f25a131746ded76ba3f0446.png

来测试一下这个方法的计算时间:

4da01664f03938bfa544dca05163b539.png

从运行结果来看,与方法一在时间上相差无几。 小结 本文着重对于含重复数字的全排列个数进行了分析,对于这类问题的较方便的解法是先整体后去重或者分步组合法,这两种计算方法相对于将全部排列都列写出来再统计而言,是一个质的飞跃,充分利用数学知识,确实对生活中的许多问题都会有极大的帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值