找出序列重新排列的方式数

时间:2012-05-21 10:35:09

标签: python permutation combinatorics

如何找到一系列数字(可能包含相似项目)的方式可以重新排列,以便数字不会放置在相同的位置或放置相似的数字。

例如,[0,0,0,1,1,1]只能以一种方式重新排列,即[1,1,1,0,0,0]

[0,0,0,1,1,1,1]无法以任何方式安排。

[1,2,2,14]可以通过两种方式排列,即[2,1,14,2], [2,14,1,2]

[1,1,2,2,14]可以通过4种方式排列,[14,2,1,1,2], [2,2,14,1,1], [2,2,1,14,1], [2,14,1,1,2]

数学解决方案可用但我正在考虑使用编程概念的一些简单方法。数学代码有点像这样..(对不起,我无法以正确的格式发布)

∫∞0 Ln1(x)..Lnr(x)e−xdx

其中r是项目数,ni是项目i的出现次数,Lk是第k个Laguerre多项式。例如,对于1,1,2,2,14,我们有r = 3,n1 = 2,n2 = 2,n3 = 1,所以重新排列的数字是

∫∞0 L2(x)L2(x)L1(x)e−xdx 
= ∫∞0 12(x2−4x+2)12(x2−4x+2)(1−x)e−xdx 
= ∫∞0(−14x5+94x4−7x3+9x2−5x+1)e−xdx
= −4

但我在想是否有任何python库可以根据我们的需要生成所有排列。

3 个答案:

答案 0 :(得分:3)

你试过itertools.permutations吗?

http://docs.python.org/library/itertools.html#itertools.permutations

import itertools

def my_combos(val):
    results = []
    l = itertools.permutations(val, len(val))
    for c in l:
        if all([x != y for (x,y) in zip(c,val)]):
            results.append(c)
    return list(set(results))


print my_combos([0,0,0,1,1,1])
print my_combos([1,1,2,2,14])

收率:

[(1, 1, 1, 0, 0, 0)]
[(2, 14, 1, 1, 2), (2, 2, 1, 14, 1), (14, 2, 1, 1, 2), (2, 2, 14, 1, 1)]

答案 1 :(得分:3)

更多参与,但在长输入序列上应该快一点:

from collections import Counter

def _rearrange(orig, rem):
    if len(orig)==1:
        v = rem[0][0]
        if v != orig[0]:
            yield [v]
    else:
        o, orig = orig[0], orig[1:]
        for i,(v,c) in enumerate(rem):
            if v != o:
                for r in _rearrange(orig, rem[:i]+([(v,c-1)] if c>1 else [])+rem[i+1:]):
                    yield [v]+r

def rearrange(orig):
    if len(orig) > 1:
        return list(_rearrange(orig, Counter(orig).items()))
    else:
        return []

def main():
    print rearrange([0,0,0,1,1,1])
    print rearrange([1,1,2,2,14])

if __name__=="__main__":
    main()

结果

[[1, 1, 1, 0, 0, 0]]
[[2, 2, 1, 14, 1], [2, 2, 14, 1, 1], [2, 14, 1, 1, 2], [14, 2, 1, 1, 2]]

编辑:比较函数的运行时,我得到:

enter image description here

(蒂姆的蓝色,我的绿色;点是数据,线条最适合(数据记录的最小平方); x轴是序列长度,y轴是运行时间,以秒为单位(对数刻度)。数据点是对于每个序列长度,在20个随机序列的每一个中运行10个中的最佳值。)

结论:

  • Tim的fn运行时增长为7.44 * * n;我的成长为3.69 * * n。

  • 在一个十项目的序列中,他的fn平均为53.9s,而我的平均为0.93s;对于序列中的每个额外项目,差异略大于双倍。

  • 他的fn具有更加一致的运行时间;我的变量很大,取决于序列中重复项目的数量。

  • 直线拟合看起来不是最好的预测因子;运行时应该是n!的函数,而不是k * * n。不过,我不知道如何对此进行建模。建议?

答案 2 :(得分:1)

使用itertools

进行暴力破解
import itertools
def arrangements(arr):
    p = itertools.permutations(arr)
    return set(item for item in p if all(x!=y for x,y in zip(item,arr)))

结果:

>>> arrangements([0,0,0,1,1,1])
{(1, 1, 1, 0, 0, 0)}
>>> arrangements([0,0,0,1,1,1,1])
set()
>>> arrangements([1,2,2,14])
{(2, 14, 1, 2), (2, 1, 14, 2)}
>>> arrangements([1,1,2,2,14])
{(2, 14, 1, 1, 2), (2, 2, 1, 14, 1), (14, 2, 1, 1, 2), (2, 2, 14, 1, 1)}