康托展开详解

        1.概述


        康托展开(Cantor Expansion)是一个相对快速的判重方法,是一种特殊的哈希函数,其复杂度为O(n^2),n是集合中元素的个数。函数康托Cantor()实现的功能是:输入一个排列,得到这个排列所对应的Cantor值。


        2.举例


表1        康托展开完成的工作

排列状态012345678012345687012345768012345786……876543210
Cantor值0123……362880-1

        表1向我们展示了0~8这9个数的全排列,共9! = 362880个,并按从小到达的顺序排序。第二行Cantor值代表了每个排列所对应的位置,例如最小的排列012345678对应了0这个位置,最大的876543210对应了362880-1这个位置。


        3.使用价值


        为什么说使用康托展开能提升判重速度呢?如表1所示,若我们使用暴力判重,每次把得到的新状态与这9个数的全排列状态9! = 362880个来对比,完成搜索+判重可能会有9! * 9!次检查(最差情况),不可行。而如果我们使用康托展开判重,完成搜索+判重只需要9! * 9^2次。对应的复杂度即为O(n! * n^2),暴力法为O(n! * n!),可以看出复杂度大大降低。


        4.原理讲解


        下面我通过将例子的方式讲解康托展开的原理:

        例子:判断2143是{1, 2, 3, 4}集合中的全排列中的第几大的数

        求解:

        {1, 2, 3, 4}共四个数,共有4! = 24种排序。计算排在2143前面的排列数目,可以将这个问题转化为求以下排列的和:

  1. 首位小于2的所有排列:比2小的只有1一个数,后面3个数有3! = 6种,写成1 * 3! = 6种。
  2. 首位为2、第二位小于1的所有排列:无,写成0 * 2! = 0种。        
  3. 前两位为21、第三位小于4的所有排列:只有3一个数,写成1 * 1! = 1种。
  4. 前三位为214、第四位小于3的所有排列:无,写成0 * 0! = 0种。

        求和:1 * 3! + 0 * 2! + 1 * 1! + 0 * 0! = 7,所以说2143是排在第八大的排列。如果用visited[24]这个数组来存放各个排列的位置的话,2143应该在visited[7]这个位置。如果我们要判重,只需要将visited[7]这个标志为改一下就行,比如原先visited[24] = {0},当我们访问过visited[7]后,将visited[7] = 1,当再次访问这个排列的时候,我们就知道已经处理过了,判重。

        根据上面的例子我们得到康托展开公式:

        把一个集合产生的全排列按字典序排序,第X个排列的计算公式如下:

                X = a[n] * (n-1)! + a[n-1] * (n-2)! + …… + a[i] * (i-1)! + …… + a[2] * 1! + a[1] * 0!

        式中,a[i]表示原数第i位在当前未出现的元素中排在第几个(从0开始),并且有0 <= a[i] < i(1 <= i <= n)。

        上述过程的反过程是康托逆展开:某个集合的全排列,输入一个数字k,返回第k大的排列。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值