字典序和康托展开

洛古刷题刷到了和字典序相关的题目

题意:

输入一个数字,判断其在从小到大字典序中的排序。

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.     第 1 位是 2, 那么以 1 打头的所有全排列一定排在这个全排列之前,那么以 1 打头的全排列有 (3!) = 6种,rank+=1∗3!=6。
  2.     第 2 位是 3,那么以 1 与 2 作为第二位的所有全排列一定在这个圈排列之前。不过我们已经让 2 打头了,因此不需要再考虑 2 占第二位的情况,只需要计算 1 占第二位的情况。 rank+=1∗2!=8。
  3.     第三位是 4,同时,我们计算以 1 占第三位的所有情况。rank=rank+1∗1!=9。
  4.     最后一位,是不需要判定的,因为前 n − 1 n - 1 n−1 位给定后,第 n 位自定。为了也适应前面推导,可以记rank=rank+0∗0!=9。

由此可得,排在 [2, 3, 4, 1] 之前的全排列共有 9 个,那么 [2, 3, 4, 1] 应当是第 10 个全排列。

总结康托展开公式为:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颜 然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值