洛古刷题刷到了和字典序相关的题目
题意:
输入一个数字,判断其在从小到大字典序中的排序。
AC代码:
#include<stdio.h>
int main()
{
char ch[10];
int a[10],num=1,z=1,t,n,str=1;
scanf("%d",&n);
scanf("%s",&ch);
for(int i=0;i<n;i++) //字符串数组转为数字直接-48或-‘0’
{
a[i]=ch[i]-48;
}
for(int i=n-2;i>=0;i--) //康托展开
{
num*=(z++);
t=0;
for(int j=i+1;j<n;j++)
{
if(a[j]<a[i])
{
t++;
}
}
str+=t*num;
}
printf("%d",str);
return 0;
}
解题核心:
1、字符串数组想要转为数字,直接在原本基础上-48或-'0'
2、康托展开
康托展开原理
举个例子,对于 1 ~ 4 的一个全排列 [1, 2, 3, 4] 和 [4, 3, 2, 1],我们知道从字典序而言,前者是该全排列集的第一个,后者是该集的最后一个。
所谓康托展开,即给定一个 n 位数的全排列,我们可以根据康托展开公式确定其应当是字典序中的第“几”个全排列。
康托展开解析
给定一个全排列,计算其字典序。直观起见,举例[2, 3, 4, 1]来说明康托展开的运作步骤:
- 第 1 位是 2, 那么以 1 打头的所有全排列一定排在这个全排列之前,那么以 1 打头的全排列有 (3!) = 6种,rank+=1∗3!=6。
- 第 2 位是 3,那么以 1 与 2 作为第二位的所有全排列一定在这个圈排列之前。不过我们已经让 2 打头了,因此不需要再考虑 2 占第二位的情况,只需要计算 1 占第二位的情况。 rank+=1∗2!=8。
- 第三位是 4,同时,我们计算以 1 占第三位的所有情况。rank=rank+1∗1!=9。
- 最后一位,是不需要判定的,因为前 n − 1 n - 1 n−1 位给定后,第 n 位自定。为了也适应前面推导,可以记rank=rank+0∗0!=9。
由此可得,排在 [2, 3, 4, 1] 之前的全排列共有 9 个,那么 [2, 3, 4, 1] 应当是第 10 个全排列。
总结康托展开公式为: