优化和改进Python代码

时间:2016-01-03 11:13:14

标签: python

def factors(n):
    t = []

    for i in xrange(1, n+1):
        if n % i == 0:
            t.append(i)

    return len(t)

def trignum(x):
    return sum(i for i in xrange(1+x))

for j in xrange(1,13000):
    if trignum(j) and factors(trignum(j))>=300:
        print factors(trignum(j))
        print trignum(j)

上面是我对项目问题12的Python尝试,运行需要很长时间,我该如何改进呢?

3 个答案:

答案 0 :(得分:1)

你浪费了大量的时间来重新计算触发器及其因素:

  

如果 trignum(j)因素( trignum(j)> = 300:

     

.... print 因素( trignum(j)

     

.... print trignum(j)

计算一次并为其分配变量,然后使用变量:

for j in xrange(1,13000):
    N = trignum(j)
    F = factors(N)
    if F>=300:
        print F
        print N

除此之外,您不必计算每j总和所有数字的触发,N(j+1)可以根据N(j)计算:N(j+1) = N(j)+j。< / p>

N = 0
for j in xrange(1,13000):
    N += j
    F = factors(N)
    if F>=300:
        print F
        print N

factors(n)中,您应该在不创建整个列表的情况下计算因子的数量。此外,你可以停止分数的一半:

def factors(n):
    nb = 2 
    for i in xrange(2, n/2+1):
        if n % i == 0:
            n+=1
    return n

答案 1 :(得分:1)

你应该估计你的算法的整体复杂性,如果你觉得它太重,找到一个更好的。如果您来这里寻求更好的算法,请编辑您的问题。我只会在问题要求时“优化和改进你的代码”。除了bigOTHER的回答之外,我建议重写你的factors函数(再一次,我没有改变任何算法,只是优化你的代码,虽然bigOTHER建议一个有价值的算法优化,即基本的动态编程)

def new_factors(n):
    return len([i for i in xrange(1, n+1) if not n%i])

如果n很大,你可以懒得保存内存。但这会慢一些。

def lazy_new_factors(n):
    return sum(not n%i for i in xrange(1, n+1))

或者你可以去numpy - 开心。 更新改进了基于NumPy的功能

import numpy as np

def numpy_factors(n):
    return n - np.count_nonzero(np.arange(1, n+1) % 2)

这是基准时间:

In [37]: %timeit factors(10000)
1000 loops, best of 3: 706 µs per loop

In [38]: %timeit new_factors(10000)
The slowest run took 4.02 times longer than the fastest. This could mean that an intermediate result is being cached 
1000 loops, best of 3: 668 µs per loop

In [39]: %timeit lazy_new_factors(10000)
1000 loops, best of 3: 1.23 ms per loop

In [40]: %timeit numpy_factors(10000)
1000 loops, best of 3: 258 µs per loop

所以,如你所见,numpy_factors获胜约3倍。由于该函数具有O(n)复杂度,因此该性能增益相对于输入大小是稳定的。纯Python new_factors也快一点。

然后我们可以用NumPy重写trignum。顺便说一下,your sum(i for i in xrange(1+x))是写sum(xrange(1+x))的过度方法。

def mod_trignum(x):
    return sum(xrange(1+x))


def numpy_trignum(x):
    return np.sum(np.arange(x+1))

基准:

In [45]: %timeit trignum(1000)
10000 loops, best of 3: 53.1 µs per loop

In [46]: %timeit mod_trignum(1000)
100000 loops, best of 3: 12.4 µs per loop

In [47]: %timeit numpy_trignum(1000)
The slowest run took 130.23 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 4.88 µs per loop

因此,我们在NumPy中获得了10倍的性能提升,在纯Python中获得了大约4倍的增益。

答案 2 :(得分:0)

一个显而易见的问题:最多N的总和可以写成O(1),作为N的单个表达式。我不会破坏你的追捕,但是一个提示:比较表面trignum的三角形:

1 x . . .
2 x x . .
3 x x x .
4 x x x x