如何从n个元素中找到k-置换的索引?

时间:2014-06-14 00:09:45

标签: algorithm permutation

我知道,对于k - p大小k,根据n元素构建,有以下内容:

P(n, k) = n! / (n - k)!

可能k - 排列。例如:

k = 2
n = 4
l = [1, 2, 3, 4]
P(n, k) = 4! / (4 - 2)! = 12

1 2 | 2 1 | 3 1 | 4 1
1 3 | 2 3 | 3 2 | 4 2
1 4 | 2 4 | 3 4 | 4 3

又一个例子:

k = 3
n = 4
l = [1, 2, 3, 4]
P(n, k) = 4! / (4 - 3)! = 24

1 2 3 | 2 1 3 | 3 1 2 | 4 1 2
1 2 4 | 2 1 4 | 3 1 4 | 4 1 3
1 3 2 | 2 3 1 | 3 2 1 | 4 2 1
1 3 4 | 2 3 4 | 3 2 4 | 4 2 3
1 4 2 | 2 4 1 | 3 4 1 | 4 3 1
1 4 3 | 2 4 3 | 3 4 2 | 4 3 2

那么,我如何找到k - 排列p的索引?考虑排列 按字典顺序生成。

修改: 我可以先找到" block" pp的第一个元素处理块。例如,对于p = [3, 2, 4]p的索引应至少为12(从0到P(n, k) - 1)。

但是,为了找到第二个元素"阻止",我必须看到剩下的项目是什么,以及它们将处于什么位置。我的意思是,我最终会在列表[1, 4]中找到,而4会在第2位,所以简单地使用元素作为键需要一些额外的操作。

我可以使用哈希来查找元素并更新其位置,但它会给我O(n^2)时间复杂度。有可能做得更好吗?

3 个答案:

答案 0 :(得分:3)

给定位置中给定数字的排列数由公式给出 (n位数位置)! /(n-k)!数字位置从左侧开始,为1。

要获得给定排列的先前排列数(即其索引),请将每个数字的公式乘以尚未使用的先前数字的数字,然后将它们相加。

实施例1,k = 2,n = 4,p = [3,4]

第一个数字,3: (4-1)! /(4-2)! *(未使用的前面的数字,2)= 6 在第一个之前有六个排列,在位置1中有3个。

第二个数字,4: (4-2)! /(4-2)! *(未使用的前面的数字,2)= 2 在第一个之前有两个排列,在位置2中有4个。

零基指数:6 + 2 = 8.

实施例2,k = 3,n = 4,p = [3,2,4]

第一个数字,3: (4-1)! /(4-3)! *(未使用的前面的数字,2)= 12 在第一个之前有12个排列,在位置1中有3个。

第二位,2: (4-2)! /(4-3)! *(未使用的前面位数,1)= 2 在第一个之前有两个排列,在位置2中有2个。

第三位,4: (4-3)! /(4-3)! *(未使用的前一位数,1)= 1 在第一个之前有一个排列,在第3个位置有4个。

零基指数:12 + 2 + 1 = 15.

答案 1 :(得分:1)

使用binary search tree(BST)。在开始之前将所有数字存储在其中,并在使用之后将其删除。要找到每个顶点的第x个元素维护.subtreeSize,只需下降树以找到所需的数字。伪代码:

    def findXth(x):
        curVertex = BST.root
        while:
            curPosition = curVertex.leftChild.subtreeSize
            if curPosition == x: return curVertex.value
            elif curPosition > x: curVertex = curVertex.leftChild
            elif curPosition < x: curVertex = curVertex.rightChild

不要忘记检查顶点的存在并删除找到的顶点。

整体复杂性将为O(n log n)。

答案 2 :(得分:0)

你可以参考下面的功能

 /**
 *  list all k or <=k size permutation of a given list with n unique elements.
 *  n can be bigger than 64. this function will take O(K^N) time, Bad.
 *
 * @param uniqueList
 * @param permutationSize
 * @param permutation
 * @param only            Only show the permutation of permutationSize,
 *                        else show all permutation of less than or equal to permutationSize.
 */
public static void my_permutationOf(List<Integer> uniqueList, int permutationSize, List<Integer> permutation, boolean only) {
    if (permutation == null) {
        assert 0 < permutationSize && permutationSize <= uniqueList.size();
        permutation = new ArrayList<>(permutationSize);
        if (!only) {
            System.out.println(Arrays.toString(permutation.toArray()));
        }
    }
    for (int i : uniqueList) {
        if (permutation.contains(i)) {
            continue;
        }
        permutation.add(i);
        if (!only) {
            System.out.println(Arrays.toString(permutation.toArray()));
        } else if (permutation.size() == permutationSize) {
            System.out.println(Arrays.toString(permutation.toArray()));
        }
        if (permutation.size() < permutationSize) {
            my_permutationOf(uniqueList, permutationSize, permutation, only);
        }
        permutation.remove(permutation.size() - 1);
    }
}

E.g。你可以认为元素是索引

public static void main(String[] args) throws Exception {
    my_permutationOf(new ArrayList<Integer>() {
        {
            add(0);
            add(1);
            add(2);
            add(3);

        }
    }, 3, null, true);
}

结果是

[0, 1, 2]
[0, 1, 3]
[0, 2, 1]
[0, 2, 3]
[0, 3, 1]
[0, 3, 2]
[1, 0, 2]
[1, 0, 3]
[1, 2, 0]
[1, 2, 3]
[1, 3, 0]
[1, 3, 2]
[2, 0, 1]
[2, 0, 3]
[2, 1, 0]
[2, 1, 3]
[2, 3, 0]
[2, 3, 1]
[3, 0, 1]
[3, 0, 2]
[3, 1, 0]
[3, 1, 2]
[3, 2, 0]
[3, 2, 1]