排列序号

题目描述:给出一个不含重复数字的排列,求这些数字的所有排列按字典序排序后该排列的编号。其中,编号从1开始。

样例:例如,排列 [1,2,4] 是第 1 个排列。


关于“字典序”和排列的相关基础概念请翻看我之前的博客(详见:点击打开链接),在这篇博客里面我还写了是如何求取一个排列的下一个排列的,如果这些内容你不清楚的话,请先打开链接回看,然后再来做这道题,因为很多内容我会当做你已经很了解字典序,故省略。

好了,这道题的意思是求一个排列的序号。那么我们先写出一个全排列,看看这些排列的规律:

比如,数字1, 2, 3构成的全排列如下:

1, 2, 3

1, 3, 2

2, 1, 3

2, 3, 1

3, 1, 2

3, 2, 1

根据之前我讲的字典序的规律(还是在博文:点击打开链接 中),我们可以发现,一个排列的顺序首先跟他的第一个字符是有关系的。第一个字符越大,其顺序越靠后。比如,上面的排列,现实两个1打头的,再是两个2打头的,最后是两个3打头的。

所以,如果我们知道了一个排列,就可以通过这个规律找到在他之前,比他打头的元素小的排列有多少个。这个与他的打头元素在所有元素中的顺序有关。

比如,现在要求排列2, 1, 4是第几个排列。首先2排在数字[1, 2, 4](升序排列)的第二位,他前面的元素只有1个,那么他前面的这些元素这个元素打头的排列有多少呢?我们可以用 x * (n - 1)! 表示。其中,x为某个排列首元素在所有元素组成的升序中前面的元素个数,n表示所有元素的个数。放到例子里,x = 1, n = 3

首元素处理完毕之后,用同样的逻辑处理第二个元素,有 x * (n - 2)!个排列在这个排列之前,但是需要注意的是这里的x表示的是整个数组中,排除第一位元素之后,小于第二位元素的所有元素的个数。拿2, 1, 4来说,x = 0

然后,再处理第三个,第四个。。。。一直到最后一个。最后将这些数相加就是这个排列之前的排列数,因为求的是第几个排列,所以再加1即可。


感觉没说清楚,举个例子吧:求排列 6, 8, 4, 7, 3, 2 是第几个排列:

1. 处理6:3 * (6 -1)! = 360

2. 处理8:4 * (6 - 2)! = 96

3. 处理4:2 * (6 - 3)! = 12

4. 处理7:2 * (6 - 4)! = 4

5. 处理3:1 * (6 - 5)! = 1

6. 处理2:0 * (6 - 6)! = 0

将上面的数字加和:360 + 96 + 12 + 4 + 1 + 0 = 473

再加1,得到474

所以,排列 6, 8, 4, 7, 3, 2为第474个排列。 

代码如下:

class Solution:
    # @param {int[]} A an integer array
    # @return {long} a long integer
    def permutationIndex(self, A):
        n = len(A)
        order = sorted(A)
        result = 0
        i = 0
        while i < n:
            temp = self.fact(n - i - 1) * order.index(A[i])
            order.remove(A[i])
            result += temp
            i += 1
        return result + 1

    def fact(self, num):
        if num == 0:
            return 0
        result = 1
        for i in range(1, num + 1):
            result *= i
        return result
        # Write your code here
第二个函数fact()用于计算阶乘。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值