作为O(n)中唯一给定索引的函数得到置换

时间:2014-08-03 14:52:47

标签: python algorithm permutation

我希望有一个函数get_permutation,在给定列表l和索引i的情况下,返回l的排列,使得排列是唯一的所有i大于0且低于n!n = len(l))。

即。所有get_permutation(l,i) != get_permutation(l,j)i!=j s.t. i j 0 <= i and j < len(l)! O(n))。

此外,此功能必须在def get_permutation(l, i): return list(itertools.permutations(l))[i] 中运行。

例如,如果指数顺序不符合要求,此函数将符合要求:

{{1}}

有没有人能解决上述问题?

编辑:我希望索引中的排列 而不是排列中的索引

5 个答案:

答案 0 :(得分:6)

如果你不关心哪些排列得到哪些索引,如果我们认为任意整数的算术运算是O(1),那么O(n)解就成为可能

例如,请参阅论文&#34; Ranking and unranking permutations in linear time&#34;作者:Wendy Myrvold和Frank Ruskey。

简而言之,有两个想法。


(1)考虑Fisher-Yates shuffle方法生成随机排列(下面的伪代码):

p = [0, 1, ..., n-1]
for i := 0 upto n-1:
    j := random_integer (0, i)
    exchange p[i] and p[j]

这种变换是单射的:如果我们给它一个不同的随机整数序列,它可以保证产生不同的排列。因此,我们用非随机整数替换随机整数:第一个是0,第二个是0或1,...,最后一个可以是从0到n-1的任何整数。


(2)有n!秩序的排列n。我们现在要做的是在factorial number system中写一个从0到n!-1的整数:最后一个数字总是0,前一个数字是0或1,......,并且有n个可能性来自第一个数字为0到n-1。因此,我们将获得一个独特的序列来为上面的伪代码提供。

现在,如果我们考虑将数字从1到n的整数除以O(1)运算,将数字转换为阶乘系统就是O(n)这样的除法。严格来说,这不是真的:对于大n,数字n!包含O(n log n)二进制数字的顺序,并且该除法的成本与数字位数成比例。


实际上,对于小n,O(n ^ 2)或O(n log n)方法来排列或取消排列,以及需要存储O(2 ^ n)或O(n!)内存的方法一些预先计算的值可能比涉及整数除法的O(n)方法更快,这在现代处理器上是相对慢的操作。 对于n足够大,使n!不适合机器字,&#34; O(n)如果订单-n!整数运算是O(1)&#34;论证停止工作。所以,如果你不坚持它理论上是O(n),那么对于小n和大n你可能会更好。

答案 1 :(得分:1)

更新:Finding n-th permutation without computing others的可能欺骗,请查看算法。

如果len(l)很小,您可以预先计算perm_index = permutations(range(len(l)))并将其用作实际数据中的索引列表列表。

此外,如果您有range(len(l))的排列列表,并且range(len(l) - 1)需要一个排列,则可以执行以下操作:

[x - 1 for x in perm_index[i][1:]]

利用了排列在生成时按排序顺序排列的事实。

答案 2 :(得分:1)

此解决方案适用于O(1)(运行时复杂性;字典查找的摊销成本):

代码

#!/usr/bin/env python

import itertools


def get_permutation():
    memoize = {}

    def _memoizer(l, i):
        if str(l) in memoize and i not in memoize[str(l)]:
            memoize[str(l)][i] = memoize[str(l)]['permutations'].next()
        else:
            p = itertools.permutations(l)
            memoize[str(l)] = {'permutations': p}
            memoize[str(l)][i] = memoize[str(l)]['permutations'].next()
        return memoize[str(l)][i]
    return _memoizer

if __name__ == '__main__':
    get_permutation = get_permutation()
    l1 = list(range(10))
    l2 = list(range(5))
    print(get_permutation(l1, 1))
    print(get_permutation(l1, 20))
    print(get_permutation(l2, 3))

输出

(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
(0, 1, 2, 3, 4, 5, 6, 7, 9, 8)
(0, 1, 2, 3, 4)

如何运作

代码将所有过去的调用存储在字典中。它还存储排列对象。因此,如果请求新的排列,则使用下一个排列。

代码使用itertools.permutations

答案 3 :(得分:0)

基于http://www.2ality.com/2013/03/permutations.html,这是一个可能的解决方案。正如@Gassa指出的那样,elements.pop按顺序不是常数,因此解决方案在列表长度上不是线性的。因此,我不会将此标记为已接受的答案。但是,它完成了这项工作。

def integerToCode(idx, permSize):                                                                                                                                       
    if (permSize <= 1):                                                                                                                                                 
        return [0]                                                                                                                                                      
    multiplier = math.factorial(permSize-1)                                                                                                                             
    digit =idx / multiplier                                                                                                                                             
    return [digit] +  integerToCode(idx % multiplier, permSize-1)                                                                                                       


def codeToPermutation(elements, code):                                                                                                                                  
    return map(lambda i: elements.pop(i), code)                                                                                                                         

def get_permutation(l, i):                                                                                                                                              
    c = integerToCode(i, len(l))                                                                                                                                        
    return codeToPermutation(list(l), c)

答案 4 :(得分:0)

有点太晚了...... C#代码可以为您提供您期望的结果:

INSTALLED_APPS