如何求n!阶乘里第k个排列

此问题来源于leetcode第60题。

题目链接

对于一个序列123,我们称123,132,213,231,312,321是它的全排列。

离散数学有一种从后向前搜索替换的方法生成下一个全排列。这种方法持续k次就可以找到第k个。

然而效率感人。

或者有一种从前向后依次交换的方法生成全排列,实际上这些方法本质上都一样,通过交换某一对数字来生成下一个排列。

但是我们可以通过一种类似于字典序生成的方法构造出第k个。

首先考察上边的序列312,这是以123这三个数字构造出的第5个排列。

我们在高中学过,对于一个排列_ _ _第一个空位可以放置3、2、1三个数字,第二个可以放置两个,第三个空位只能放置一个。

因此这叫排列的种数———n!

1 2 3 三个数字在数组中的  有序位置 分别是第0,1,2位。

我们现在看看k是怎么来的。

312为什么排第5位(序号为4)

我们可以理解为2*(2!)+0*(1!)+0*(1!)

这样看有点不太明显。

我们这次用题目的示例:

输入: n = 4, k = 9
输出: "2314"

数字组为:1234,求序号为8(k=9)的排列

那么答案是2314,

那就是1*(3!)+1*(2!)+0*(1!)+0*(0!)=1*6+1*2+0*1+0*1=8

巧合吗?

当然不是。

上面的连加等式第一项:我选择了2,那么2在1234序号为1,剩下三个都在我后面,排列数为3!

第二项:我选择了3,在134中序号为1(2被用过了),剩下两个在我后面,排列数为2!

。。。

懂了吗?这就是构造的方法。

然后我们以数学的角度分析一下这个连加等式为什么正确。

当我从0~n-1个有序数字中选择了第i大的i,那么相当于n个_位置的第一个被选择了。如果_里是0,1,2....i-1的话,那么就有

i*(n-1)!个数字比i______(_有n-1个)小。

所以依次推理,就能得到最终的结果。

而且针对这个题目来说。从剩下数字中选择一个第i大的数字代价很小,因此,可以直接用数组来处理。

这道题答案代码如下:

class Solution:
    def getPermutation(self, n: int, k: int) -> str:
        arr=[str(i) for i in range(1,n+1)]
        ans=[]
        fac=[1]
        for x in range(1,n):
            fac.append(fac[-1]*x)#生成一系列阶乘数值
        k-=1
        for _ in range(n):
            f=fac.pop()
            i=k//f
            k=k-f*i
            ans.append(arr.pop(i))

        return ''.join(ans)

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值