重新排列有界元素运动

时间:2014-04-09 12:52:53

标签: arrays algorithm permutation

我希望通过以下条件重新排列(或置换)数组元素:

  

每个元素的位置不应超过k位置

然后我想有效地重复所有这样的重排。

生成重排的最快方式是什么?

我知道复杂性会低于O((2k+1)^n),我正在寻找这种算法的最有效实现。

我正在寻找一种可以击败天真算法的解决方案,该算法考虑每个排列并检查条件。

1 个答案:

答案 0 :(得分:1)

这是一个时间O(n P)算法,其中P是排列的数量。假设你要在每个排列上运行一些线性时间或更差的东西,这是渐近最优的(尽管Knuth可能会对此有所说明)。

用于生成所有排列的惯用递归算法就是这样。

def swap(array, i, j):
    array[i], array[j] = array[j], array[i]

def perms(array, start=0):
    if start >= len(array):
        print(array)
    else:
        for i in range(start, len(array)):
            swap(array, start, i)
            perms(array, start + 1)
            swap(array, start, i)

我要做的修改背后的想法是有效地修剪不产生输出的子树。假设每次递归调用的工作是O(1),剩余的叶子为其他调用付费。

首先我们进行修改以跟踪逆置换。

def swap(array, indices, inverse, i, j):
    array[i], array[j] = array[j], array[i]
    indices[i], indices[j] = indices[j], indices[i]
    inverse[indices[i]] = i
    inverse[indices[j]] = j

def perms(array, indices, inverse, start=0):
    if start >= len(array):
        print(array)
    else:
        for i in range(start, len(array)):
            swap(array, indices, inverse, start, i)
            perms(array, indices, inverse, start + 1)
            swap(array, indices, inverse, start, i)

现在我们使用逆修剪。关键不变量是符合条件start的元素位于start和以下k个位置。符合条件后,元素在选定之前或start变得过大之前仍然符合条件。反过来帮助我们避免后一种情况。

def perms(array, indices, inverse, k, start=0):
    if start >= len(array):
        print(array)
    elif start - k >= 0 and inverse[start - k] >= start:
        i = inverse[start - k]
        swap(array, indices, inverse, start, i)
        perms(array, indices, inverse, k, start + 1)
        swap(array, indices, inverse, start, i)
    else:
        for i in range(start, min(start + k + 1, len(array))):
            swap(array, indices, inverse, start, i)
            perms(array, indices, inverse, k, start + 1)
            swap(array, indices, inverse, start, i)

你应该能够做到

n = 8   # for example
k = 3   # for example
array = list(range(n))
indices = list(range(n))
inverse = list(range(n))
perms(array, indices, inverse, k)

并查看结果排列。