几点评论。
正如 Quincunx 所写,您只需要检查从 1..sqrt(n) 开始的整数范围,这将转化为类似 this的内容for i in xrange(1, sqrt(n) + 1): ...
。仅此优化就可以大大加快速度。
您可以使用三角形数公式(直到现在我才知道,谢谢 Quincunx),或者您可以使用另一种方法来查找三角形数,而不是递归和字典查找。您只需要序列中的下一个数字,因此保存它没有意义。函数调用在 Python 中涉及大量开销,因此通常不建议将递归用于数字运算。另外,为什么演员表float
,我不太明白?
我看到您已经在使用xrange
而不是range
构建int
流。我假设您知道这xrange
更快,因为它是作为生成器函数实现的。你也可以那样做。这也使事情变得更加顺利。
我试图做到这一点,使用生成器,下面的代码在我的机器(YMMV)上找到约 16 秒内的第 500 个三角形数。但我还使用了一个巧妙的技巧来找到除数,即二次筛。
这是我的代码:
def triangle_num_generator():
""" return the next triangle number on each call
Nth triangle number is defined as SUM([1...N]) """
n = 1
s = 0
while 1:
s += n
n += 1
yield s
def triangle_num_naive(n):
""" return the nth triangle number using the triangle generator """
tgen = triangle_num_generator()
ret = 0
for i in range(n):
ret = tgen.next()
return ret
def divisor_gen(n):
""" finds divisors by using a quadrativ sieve """
divisors = []
# search from 1..sqrt(n)
for i in xrange(1, int(n**0.5) + 1):
if n % i is 0:
yield i
if i is not n / i:
divisors.insert(0, n / i)
for div in divisors:
yield div
def divisors(n):
return [d for d in divisor_gen(n)]
num_divs = 0
i = 1
while num_divs < 500:
i += 1
tnum = triangle_num_naive(i)
divs = divisors(tnum)
num_divs = len(divs)
print tnum # 76576500
在我简陋的机器上运行它会产生以下输出:
morten@laptop:~/documents/project_euler$ time python pr012.py
76576500
real 0m16.584s
user 0m16.521s
sys 0m0.016s
使用三角形公式而不是天真的方法:
real 0m3.437s
user 0m3.424s
sys 0m0.000s