2 的幂的 python itertools 排列太慢

标签 python performance permutation python-itertools

我遇到了一个非常奇怪的问题,似乎找不到解决方法。

以下代码找到 n 的质因数分解,将质因数放入列表中,然后找出质因数的所有可能的和变化,并打印出该列表的唯一值。

示例:44 的质因数是 2*2*11,所以 44 会打印出来

2,2+2,11,2+11,2+2+11 = 2,4,11,13,15:

这是我的代码:

import math
import sys
import itertools
from itertools import permutations

def primes(n):
    primfac = []
    d = 2
    while d*d <= n:
        while (n % d) == 0:
            primfac.append(d)
            n //= d
        d += 1
    if n > 1:
       primfac.append(n)
    return primfac


def primecombo(n):
    b = []
    for i in range(1, len(primes(n))+1):
        for subset in permutations(primes(n), i):
            b.append(sum((subset)))
    a = list(set(b))
    a.sort()
    return a

代码本身在大多数情况下似乎都可以正常高效地工作,但是由于某些非常奇怪的原因,当您处理任何只有质因数是 2 的数字时,它会变得非常慢。

如果您尝试 print primecombo(444444) 或 print primecombo(23452823),它几乎会立即打印结果,但如果您尝试 2048 或 4096,它会变得非常非常慢。

谁能看出为什么会这样,我能做些什么来解决这个问题?

最佳答案

简答

使用 itertools.permutations 可以让您的算法对素因子的冗余分区求和。使用 itertools.combinations 应该是一个相当大的改进,但我们仍然可以做得更好。

长答案

使用 itertools.permutations 查找所有排列会使您的函数 primecombo 在因子数量方面以阶乘时间运行,比指数更差。

让我们看一下与因子数 k 相关的时间复杂度。主要步骤是遍历 permutations(primes(n), len(primes(n))。有 k! 个排列,您要对每个排列求和。时间-因此你的算法的复杂性是

O(k * k!)

这就是为什么有 11 个因子的 2048 要处理的时间比有 7 个因子的 23452823 长得难以忍受。

备选

幸运的是,无需访问每个排列。例如,如果您有因子 2、3 和 4,您将对 2、3 和 4 的每个冗余排列求和。一个快速的改进是改为对组合求和,但即便如此,当存在不止一次出现的因素时,我们有时会对同一分区求和两次。

以下解决方案通过使用 Counter 而不是 list 来跟踪主要因素来解决此问题。这稍后允许我们使用 itertools.product

此算法能够在几毫秒内找到 4096 所需的总和,请参阅下面的时间复杂度分析。

import itertools
from collections import Counter

def primes(n):
    primfac = Counter()
    d = 2

    while d ** 2 <= n:
        while (n % d) == 0:
            primfac[d] += 1
            n //= d
        d += 1

    if n > 1:
       primfac[n] += 1

    return primfac

def primecombo(n):
    factor_sums = [[p * e for e in range(exp + 1)] for p, exp in primes(n).items()]

    sums = set(sum(partition) for partition in itertools.product(*factor_sums))

    return sums

primecombo(4096) # {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24}

时间复杂度

时间复杂度取决于主要因素的分布。如果有 k 个不同的因素,最坏的情况就会出现。我们的 itertools.product 的大小为 2k。从而使算法

O(k * 2k)

关于2 的幂的 python itertools 排列太慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49795270/

相关文章:

python - asyncio 收集产生的结果

performance - Haskell:并发数据结构指南

c# - Linq 性能 : Any vs. 包含

Scala 生成列表的排列耗尽内存

python - 从排列列表中获取所有独特的组合

python - 有效地计算组合和排列

python - 从类内部访问包含的静态信息的更好/正确方法

python - 将列表划分为偏移量为 1 的子列表

python - 集合的 all() 方法的逻辑

c++ - 使用许多外部类型声明时如何加快编译时间