我已将以下代码放在一起,以确定数字是否具有奇数或偶数的除数。该代码适用于相对较小的数字,但一旦输入更大的数字,如9位数,它就会挂断。
def divisors(n):
num = len(set([x for x in range(1,n+1) if not divmod(n,x)[1]]))
if (num != 0 and num % 2 == 0):
return 'even'
else:
return 'odd'
我该怎么做才能提高效率呢?
答案 0 :(得分:2)
这是你的问题:
num = len(set([x for x in range(1,n+1) if not divmod(n,x)[1]]))
这构造一个列表,然后构造该列表的一个集合,然后获取集合的长度。您无需执行任何相关操作(range()
或xrange()
,因此不会生成重复的对象,因此我们不需要该集合,sum()
可以正常工作在任何可迭代对象上,所以你不需要列表)。当我们讨论这个主题时,divmod(n, x)[1]
只是一种非常精细的编写n % x
的方式,并且消耗了一些额外的内存来构造一个元组(由于你把元组扔掉而立即回收) )。这是固定版本:
num = sum(1 for x in xrange(1,n+1) if not n % x)
答案 1 :(得分:2)
您不需要测试每个可能的除数,测试到sqrt(n)就足够了。这将使您的函数O(sqrt(n))而不是O(n)。
import math
def num_divisors(n):
sqrt = math.sqrt(n)
upper = int(sqrt)
num = sum(1 for x in range(1, upper + 1) if not n % x)
num *= 2
if upper == sqrt and num != 0:
num -= 1
return num
在使用python2的基准测试中,这比使用sum(1 for x in range(1, n + 1) if not n % x)
的{{1}}快1000倍,而对于1e8则快10000倍。对于n = int(1e6)
,后面的代码给了我一个内存错误,暗示整个序列在执行求和之前存储在内存中因为在python 2中1e9
返回一个列表而我应该使用range()
代替。对于python3 xrange()
没问题。