Permutation Index

Problem

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

Example

Given [1,2,4], return 1.

Note

我觉得虽然在LC里分类是Easy,但其实是一道难题。思路如下:
搞一个哈希表,存储数组A中每一位A[i]的后面小于它的数的个数count。
为什么这样做呢,因为按照lexicographical order,小的数应该排在前面。那么A[i]后面小于A[i]的数有count个,而i前面又应该有n-i-1位,有(n-1-i)的阶乘种排列的可能,所以应该排在A[i]之前的可能排列就有count * (n-1-i)!个:所以遍历A[]中每一个数,计算在其之前的自然排列的数目,这些数目相加之和存入res,那么res的下一个数字就是现在数组A[]的排列。

对题目有了思索和理解之后,可以找找简化一点的办法。有没有可能不使用HashMap,也能够记录阶乘呢?只要从最后一位fact = 1开始, 向高位阶乘,直到最高位fact = A.length!

Solution

1.

public class Solution {
    public long permutationIndex(int[] A) {
        int n = A.length;
        long res = 0;
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < n; i++) {
            int count = 0;
            for (int j = i+1; j < n; j++) {
                if (A[i] > A[j]) count++;
            }
            map.put(A[i], count);
        }
        for (int i = 0; i < n; i++) {
            long fact = 1;
            for (int j = n-1-i; j > 0; j--) {
                fact *= j;
            }
            res += map.get(A[i]) * fact;
        }
        return ++res;
    }
}

2.

public class Solution {
    public long permutationIndex(int[] A) {
        if (A == null || A.length == 0) return 0;
        long fact = 1, index = 0;
        for (int i = A.length-1; i >= 0; i--) {
            int rank = 0;
            for (int j = i+1; j < A.length; j++) {
                if (A[j] < A[i]) rank++;
            }
            index += rank * fact;
            fact *= (A.length-i);
        }
        return index+1;
    }
}

vs. i increases in for loop

//这种思路是从高位向低位计算当前位剩余排列总数,阶乘逐位减小,理解起来就没有那么直观了。

public class Solution {
    public long permutationIndex(int[] A) {
        if (A == null || A.length == 0) return 0;
        long index = 0, fact = 1;
        for (int i = 1; i <= A.length; i++) fact *= i;
        for (int i = 0; i < A.length; i++) {
            int rank = 0;
            for (int j = i+1; j < A.length; j++) {
                if (A[j] < A[i]) rank++;
            }
            fact /= (A.length-i);
            index += rank * fact;
        }
        return index+1;
    }
}

Permutation Index II

Problem

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.

Note

与上一题的不同之处时会有重复的数。那么,只要在发现是重复数的那一位用rank * fact的结果除以重复的次数dup再加入index就可以了。当然,每个重复数的dup都要阶乘,例如有3个2,4个8,dup就是3! * 4! = 144index是所有previous排列的次数和,返回下一次index+1

Solution

public class Solution {
    public long permutationIndexII(int[] A) {
        long index = 0, fact = 1, dup = 1;
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = A.length-1; i >= 0; i--) {
            if (!map.containsKey(A[i])) map.put(A[i], 1);
            else {
                map.put(A[i], map.get(A[i])+1);
                dup *= map.get(A[i]);
            }
            int rank = 0;
            for (int j = i+1; j < A.length; j++) {
                if (A[j] < A[i]) rank++;
            }
            index += rank * fact / dup;
            fact *= (A.length - i);
        }
        return index+1;
    }
}

linspiration
161 声望53 粉丝