Middle算法——计算当前排列的序号

题目描述

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

样例1:

输入:[1,2,4]
输出:1

样例2:

输入:[3,2,1]
输出:6

题目分析

本题本身是一个考察排列组合序号的算法,给出一个组合,比如1,2,4,那么它的排列组合数为:

  • 1,2,4
  • 1,4,2
  • 2,1,4
  • 2,4,1
  • 4,1,2
  • 4,2,1

这六种,从小到大排列,如果给出输入为1,4,2,则输出2,因为它排组合中第二大。

核心点在于——第N大,则输出N。

思路制定

既然是找本序列的位次N,那么我们来简单找一下规律——如果我给出4,1,2,你一定可以很快发现,它是第五大的序列。

为什么?

很简单,因为百位数是4,那么起码大于了百位数为1和2的情况(4种),十位为1,没有比十位为1更小的情况,个位为4,在这种情况下没有比个位为1更小的情况。

规律找到——即找到当前位置的数为第N大,则有(n-1)*(位数-1)!比它小

比如4,是百位数,第三大,则有(3-1)*2!个数比它小。

转换伪代码

思路缺点,想转换伪代码则非常简单了。

for i :序列:

        for j:剩下的序列:

                计算i比多少个j大,并赋值于count

        总位+=(count-1)*(位数-1)!

return 总位

话不多说,上代码!
 

public class Solution{
    public long permutationIndex(int[] a){
        long allcount=0l;//初始化总数
        int n=a.length;//先转移a的length,避免多次取值耗损时间
        int[] x=new int[n];
        long allgroup=1l;//先计算出总的位数阶乘,每次计算后/当前位次
        for(int i=1;i<n;i++){
            allgroup*=i;
        }
        for(int i=0;i<n;i++){
            int count=0;
            for(int j=i+1;j<n;j++){
                if(j!=n){//这里其实提前令i<n-1即可,但当时写代码太快,没太注意细节
                    if(a[i]>a[j]){
                    count++;
                    }
                    
                }
            }
            allcount+=(count*allgroup);
            if(allgroup>1){
                allgroup/=(n-i-1)
            }
        }
        return allcount+1;
    }
}

这套代码是过了lintcode的内存和速度要求的,也就是说,大致时间空间复杂度是ok的,不过这套算法的速度很明显是排在末尾的。问题在哪?

来看我博客的,大多是学生和菜鸟学习阶段,所以这个问题Mo交给认真阅读的同学,如果你对它有兴趣,并且发现了我编写的漏洞,可以在下面讨论,实在想不到的同学,也可以私聊我,我会详细给同学们解答。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值