码迷,mamicode.com
首页 > 其他好文 > 详细

lintcode10- Permutation Index II- medium

时间:2017-11-05 10:50:55      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:amp   put   重复   color   不能   返回   get   generate   个数   

Given a permutation which may contain repeated numbers, find its index in all the permutations of these numbers, which are ordered in lexicographical order. The index begins at 1.

Example

Given the permutation [1, 4, 2, 2], return 3.

 

算法:和前面一题都是事先数学想法。有重复时,每一个位idx加和的公式是:贡献 = 后面小的数的个数  *  后面数字个数  /  能用来排列的数字里重复次数的阶乘M。 M 比较复杂,它跟具体后面哪个数字被换到前面来有关,因为不同数被换到这一位后,后面能用来排列的数不一样,具体组成是,后面本来的数 - 被换到前面的数 + 换到后面去的数。

看一看例子 3,5,5,6,7,3,2,1,1  。比如要算第一个‘3’位上的贡献,其实就是看后面曾经换到这个位置上的数,产生过多少种排列。因为有重复数字,问题没有那么简单,每个数字换到第一位后,剩余数字还有没有重复,能产生多少种排列的情况就都不相同了,所以一定要二重循环遍历每种后面的小的数字换到这个位置产生排列的可能。 具体比如说把后面的‘1’ 换到第一个位置来,‘3’这时候被换到后面去了,那这个‘1’产生的贡献就是用“3,5,5,6,7,3,2,3,1”这么多数字能产生多少种排列。其实就是全排列/ 重复次数阶乘的积,除掉阶乘积是因为你要保证5,5你只算5a,5b有效,如果有3个6,那你只算6a,6b,6c有效,这样就能去重了,阶乘表示的就是这几个小数字内部的全排列,积表示的就是可能有好几套重复,55,666。

细节:不能把后面两个1都换到前面去,这里是另一个去重,用set避免一下。

public class Solution {
    /**
     * @param A an integer array
     * @return a long integer
     */
    long fac(int numerator) {
        long now = 1;
        for (int i = 1; i <= numerator; i++) {
            now *= (long) i;
        }
        return now;
    }   
    
    // 返回  后面多少数! / 后面重复数阶乘的积
    long generateNum(HashMap<Integer, Integer> hash) {
        long denominator = 1;
        int sum = 0;
        for (int val : hash.values()) {
            if(val == 0 )    
                continue;       
            denominator *= fac(val);
            sum += val; 
        }       
        if(sum==0) {
            return sum; 
        }       
        return fac(sum) / denominator;
    }   

    public long permutationIndexII(int[] A) {
        HashMap<Integer, Integer> hash = new HashMap<Integer, Integer>();

        for (int i = 0; i < A.length; i++) {
            if (hash.containsKey(A[i]))
                hash.put(A[i], hash.get(A[i]) + 1);
            else {      
                hash.put(A[i], 1);
            }           
        }       
        long ans = 0;
        for (int i = 0; i < A.length; i++) {
            HashMap<Integer, Integer> flag = new HashMap<Integer, Integer>(); 
            
            //遍历每一个i后面的数字,如果小而且没有被换到这位过的话,试着换换看算它换到这位后,后面数字的排列方法。
            for (int j = i + 1; j < A.length; j++) {
                if (A[j] < A[i] && !flag.containsKey(A[j])) {
                    // 标记一下,下次不要再选这个重复数[3,5,5,6,7,2,1,1] 不要两个1都换到前面试
                    flag.put(A[j], 1);
                    // 自己被换到前面了,等会不参与后面数字的排列,去掉
                    hash.put(A[j], hash.get(A[j])-1);
                    // 算出后面多少数! / 后面重复数阶乘的积
                    ans += generateNum(hash);
                    // 把修改变回来,为下一个小数换上来做准备
                    hash.put(A[j], hash.get(A[j])+1);
                }

            }
            // 以后数字i用后面的数字算全排列再也不能用这一位了,只能往后看
            hash.put(A[i], hash.get(A[i])-1);
        }
        return ans + 1;
    }
}

 

lintcode10- Permutation Index II- medium

标签:amp   put   重复   color   不能   返回   get   generate   个数   

原文地址:http://www.cnblogs.com/jasminemzy/p/7786764.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!