Lintcode(198) Permutation Index II

查找存在重复元素中排列的序号


这道题基于查找不存在重复元素中排列序号的基础之上,

即P(n) = P(n-1)+C(n-1)

C(n-1) = (首元素为小于当前元素,之后的全排列值)

P(1) = 1;

而不存在重复元素的全排列值C(n-1) = (n-1)!*k(k为首元素之后小于当前元素的个数)



在存在重复元素的排列中首先全排列的值的求法变为:

C(n-1) = (n-1)!/(A1!*A2!*···*Aj!)*k(其中Ai 为重复元素的个数,k为小于首元素前不重复的个数)

宠儿得到如下代码: 

class Solution {
public:
    /**
     * @param A an integer array
     * @return a long integer
     * The index of vector A is the Full Permutation when the first number
     * replace to number which behind it and smaller than it
     * and then iterator to next elements until to the end.
     * and repeat numbers Full Permutation = n!/(repeat numbers!)
     * just map to ps[n]/tmp in the code
     */
    long long permutationIndexII(vector<int>& A) {
        // Write your code here
        int n = A.size();
        if(!n) return 0;
        long long *ps = new long long [n];// records Factorial of n
        ps[0] = 1;
        for(int i=1;i<n;i++){
            ps[i] = ps[i-1]*(i+1);
        }
        long long res = 1;
        int j,start,k;
        unordered_map<int,int> cnts;//records counts of each number behind i
        cnts[A[n-1]] = 1;// from n-1 point
        long long tmp = 1;//current value results to ps[n-2-i]/tmp (tmp means the repeat numbers' Factorial which behind i like Permutation(1122) = 4!/(2!*2!)  or Permutation(111122)= 6!/(4!*2!) just map to ps[n]/tmp)
        for(int i=n-2;i>=0;i--){
            start = A[i];
            cnts[A[i]]++;
            for(j = i + 1 ; j < n ; j++){
                if(A[i] <= A[j]) break;//no more elements smaller than A[i]
                if(start == A[j]) continue;//element has been visited
                else {//new element which smaller than A[i] and haven't been visited
                    start = A[j];
                    res += ps[n-i-2]/(tmp * cnts[A[i]] / cnts[A[j]]);
                }
            }
            tmp *= cnts[A[i]];
            j--;
            //sort elements behind i
            if(i != j){
                start = A[i];
                for(k=i;k<j;k++){
                    A[k] = A[k+1];
                }
                A[j] = start;
            }
        }
        return res;
    }
};


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值