【问题标题】:Find the number of ways a sequence can be rearranged找出序列可以重新排列的方式数
【发布时间】:2012-05-21 10:35:08
【问题描述】:

我如何找到可以重新排列数字序列(可能包含类似项目)的方式的数量,以使数字不会放置在与其或类似数字相同的位置。

例如,[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 个拉盖尔多项式。例如,对于 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 库可以生成我们想要的所有排列。

【问题讨论】:

    标签: python permutation combinatorics


    【解决方案1】:

    您是否尝试过 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)]
    

    【讨论】:

    • 嘿 thnx.. 对“itertools”的启发:)
    【解决方案2】:

    涉及更多,但在长输入序列上应该更快:

    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]]
    

    .

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

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

    结论:

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

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

    • 他的 fn 的运行时间更加一致;我的是高度可变的,取决于序列中重复项的数量。

    • 直线拟合看起来不是最好的预测器;运行时应该是 n! 的函数,而不是 k * * n。不过,我不确定如何建模。有什么建议吗?

    【讨论】:

    • @FirstRock:你最好通过支持所有好的答案并接受最好的答案来表达你的感谢,而不是真正的感谢。请阅读有关投票系统的常见问题解答。谢谢,欢迎。
    • 任务完成:) 实际上那个时候没有必要的权限来做。
    【解决方案3】:

    蛮力使用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)}
    

    【讨论】:

    • 感谢您的编辑.. 答案简短而甜蜜 :) 我正在使用这个 :) 因为我必须输出编号。我在设置之前使用 len() 函数的方式,它给出了整数作为输出..
    猜你喜欢
    • 2012-08-30
    • 1970-01-01
    • 2020-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-16
    • 2011-05-02
    相关资源
    最近更新 更多