我有这三个素因子函数,我不明白它们的时间复杂性的差异。
这是我开始时的第一个功能,希望更快。我已经有了一个非常快速的素数功能,但我认为Sieve会更快。
def is_prime(i):
if i <= 1: return False
if i <= 3: return True
if i%3 == 0 or i%2 == 0: return False
return sum((1 for y in xrange(5, int(i**0.5)+1, 6) if i%y == 0 or i%(y+2) == 0)) == 0
prime_factors_1 = lambda x: [i for i in range(1,x) if x%i == 0 and is_prime(i)]
这是我在这个家伙博客上发现的Eratosthenes Sieve的实施:http://www.drmaciver.com/2012/08/sieving-out-prime-factorizations/
def prime_factorizations(n):
sieve = [[] for x in xrange(0, n+1)]
for i in xrange(2, n+1):
if not sieve[i]:
q = i
while q < n:
for r in xrange(q, n+1, q):
sieve[r].append(i)
q *= i
return sieve[-1]
我喜欢尝试改进我发现的示例,我喜欢尝试减少行数,同时保留功能和时间/空间效率。我可能已经对这个列表理解过度了。
def prime_factors_2(n):
factors = [[] for n in xrange(0,n+1)]
[[[factors[r].append(i) for r in xrange(q, n+1, q)] for q in range(i,n,i)] for i in (y for y in xrange(2,n+1) if not factors[y])]
return factors[-1]
我定时并得到了这个输出:
prime_factorizations: 1.11333088677
prime_factors_1: 0.0737618142745
prime_factors_2: 10.7310789671
有些事情我不明白这些时间:
答案 0 :(得分:2)
为什么非筛子最快?
其他功能可以产生大量的工作来产生您不关心的数字因素。
为什么列表理解的筛子这么慢?
因为你搞砸了。这部分:
[[[factors[r].append(i) for r in xrange(q, n+1, q)] for q in range(i,n,i)] for i in (y for y in xrange(2,n+1) if not factors[y])]
# ^^^^^^^^^^^^^^^^^^^^^
不等同于原始代码中的while
循环,它将q
乘以i
而不是添加i
。即使你已经把它弄好了,但是使用列表理解副作用会让人感到困惑,这与列表推导的目的相反,并且浪费了你构建的Nones巨大嵌套列表的空间。
什么算法会比我原来的非筛子更快?
您可以将您找到的素数因子分开,从而无需检查以后的素数因素,并减少您需要检查的因素数量:
def prime_factors(n):
factors = []
if n % 2 == 0:
factors.append(2)
while n % 2 == 0:
n //= 2
candidate = 3
while candidate * candidate <= n:
if n % candidate == 0:
factors.append(candidate)
while n % candidate == 0:
n //= candidate
candidate += 2
if n != 1:
factors.append(n)
return factors