康托展开基本运用

引入

首先,让我们来看一个题
题目:康托展开
题目描述:给出一个数N,再给出N的全排列的某一个排列,问该排列在全排列中的次序是多少?例如3的全排列中,123排第一位,321排最后一位
输入第一行为一个数N,第二行为N的全排列的某一个排列
输出一个整数,表示该排列在全排列中的次序
样例:输入:3
1 2 3
输出:1

题目理解

很多人看到这个题目会感到十分的简单,只需要将这个数的全排列求出来,之后遍历求出来的数组并输出问题位置就好,但我们要知道,之前全排列的方法的时间复杂度是O(n!),也就是说如果我们要在这个题上用之前的方法,遇到较大的数就会空间或时间超限。那么,我们就可以引入我们的康托展开

康托展开

基本概念

对于康拓展开,百度百科(文言文)上是这样说的:康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。
这句话并不是很难理解,就是将一个全排列用康托展开压缩成一个数(他的位置)进行存储,同时也可以将这个数进行康托的逆运算求出全排列。

压缩方法

对于康托展开我们有一个公式: X = a n × ( n − 1 ) ! + a n − 1 × ( n − 2 ) ! + ⋯ + a 1 × 0 ! X=a_n \times(n-1)!+a_{n-1} \times(n-2)!+\cdots+a_1 \times 0! X=an×(n1)!+an1×(n2)!++a1×0!
我们可以举一个例子:在 ( 1 , 2 , 3 , 4 , 5 ) (1,2,3,4,5) 1,23,45的全排列中,求34152的康托展开值。
首位是3,则小于3的数有两个,为1和2, a [ 5 ] = 2 a[5]=2 a[5]=2,则首位小于3的所有排列组合为 a [ 5 ] ∗ ( 5 = 1 ) ! a[5]*(5=1)! a[5](5=1)!
第二位是4,由于第一位小于4,1、2、3中一定会有1个充当第一位,所以排在4之下的只剩2个,所以其实计算的是在第二位之后小于4的个数。因此 a [ 4 ] = 2 a[4]=2 a[4]=2
第三位是1,则在其之后小于1的数有0个,所以 a [ 3 ] = 0 a[3]=0 a[3]=0
第四位是5,则在其之后小于5的数有1个,为2,所以 a [ 2 ] = 1 a[2]=1 a[2]=1
最后一位就不用计算啦,因为在它之后已经没有数了,所以a[1]固定为0
对于公式来说: X = 2 × 4 ! + 2 × 3 ! + 0 × 2 ! + 1 × 1 ! + 0 × 0 ! = 61 X=2 \times4!+2 \times3!+0 \times2!+1 \times1!+0 \times0!=61 X=2×4!+2×3!+0×2!+1×1!+0×0!=61,所以比34152小的排列有61个,即34152是第62个

模板代码

对于康托展开,也是有一套固定的模板代码的

int num[1000];
long long kt(int a[],int n){
	long long s=1;
	long long p[1000];
	for(int i=0;i<n-i;i++){			//计算阶乘(如果题目要求小可以直接用数组写出)
	s*=i+1;
	p[i]=s;
	}
	long long sum=1;
	for(int j=i+1;j<=n;j++){		//套用公式
		if(num[i]<num[j]{
			s++;
		}
		sum+=s*p[n-2-i];
	}
	return sum;			//此时sum即为康托展开值
}

总结

这便是康托展开的基本运用,如果有错误欢迎指正,会尽力修改完善

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值