leetcode#60 排列序列

leetcode#60 排列序列

题目:

给出两个数n,k,求1~n的第k个全排列(字典序)。

思路:逆康托展开

康托展开

给个排列问是第几个。
先给出结论:康托展开的结果为ans=A[0] * (n-1)!+A[1] * (n-2)!+A[2]*(n-3)!+…。==
其中A[i]代表 位于位置i后面的数小于A[i]值的个数,然后乘上后面的位数的阶乘。
不难理解,设序列p=abcdefg,那么对任意比p小的数列,一定存在前i位与p相同第i位比i小,后i位随意排列。因此,对于任意i,满足的条件数就是后面比i小的数的个数和,后面位数的阶乘。这是对于第i位来说,小的数的个数,如果第i位不变,那么就要继续看后面的位,所以是累加和的关系。

逆康托展开

也就是这个题了。
看康托展开的结论可以看出,每一项的(n-i)!都比后面所有项的总和还大。于是可以用类似进制转换的方法,不断地模、除,来得到A的每—项。
前面已经说到康拖展开是从序列到自然数的映射且是可逆的,那么逆康拖展开便是从自然数到序列的映射列 :

在(1,2,3,4,5) 给出61可以算出起排列组合为34152
具体过程如下:
用 61 / 4! = 2余13,说明 ,说明比首位小的数有2个,所以首位为3。
用 13 / 3! = 2余1,说明 ,说明在第二位之后小于第二位的数有2个,所以第二位为4。
用 1 / 2! = 0余1,说明 ,说明在第三位之后没有小于第三位的数,所以第三位为1。
用 1 / 1! = 1余0,说明 ,说明在第二位之后小于第四位的数有1个,所以第四位为5。

细节:除完后,不能直接赋值商加1,因为,设商为2,说明比这位小的有两个,并不一定是3,因为可能有的数已经被用过了,所以,要取剩下的第三个数。

代码:

class Solution
{
public:
    int fact[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
    string getPermutation(int n, int k)
    {
        k--;
        string ans;
        vector<int> ve;
        for (int i = 1; i <= n; ++i)
            ve.push_back(i);
        for (int i = 1; i <= n; ++i)
        {
            int x = k / fact[n - i];
            k %= fact[n - i];
            ans.push_back(ve[x]+'0');
            ve.erase(ve.begin() + x);
        }
        return ans;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值