所以我正在使用1 000 000个密钥在字典上工作,我的任务是让它在3秒内工作(在Intel 2.4 GHz上)。我尝试分析我的代码并且while循环有很多命中,但我无法找到一种方法来让我的代码在没有它的情况下运行得更快。有没有办法改进我的代码,以使其更快地工作?
代码应该(并且它会这样做,但是太慢)创建一个字典,其中键都是从2到999999的整数,并且值是从序列模式生成的列表的长度。模式是:如果整数是偶数,则将其除以2,如果整数是奇数且大于1,则将其乘以3并加1。这将持续到我们达到数字1。
示例:3 - > 10 - > 5 - > 16 - > 8 - > 4 - > 2 - >这个清单的长度是8。
代码:
import time
start = time.clock()
first = 2
last = 1000000
def function1(n,d):
if n/2 in d:
d[n] = d[n/2] + 1
if n not in d:
d[n] = 0
temp = n
while temp > 1:
if temp%2 == 0:
temp /= 2
d[n] += 1
else:
temp = 3*temp + 1
d[n] += 1
if temp in d:
d[n] += d[temp]
break
return d[n]
d={}
d[1]=1
d={key: function1(key,d) for key in range(first,last)}
print(time.clock() - start)
答案 0 :(得分:4)
在我的系统上,你的代码确实需要花费不到3秒的时间(在最新的2.3 GHz Intel Core i7 Macbook Pro上使用Python 3.4)。
通过使用局部变量并避免两次构建字典,我可以在3秒内(到2.65秒,减少12%)得到它:
def function1(n,d):
if n/2 in d:
d[n] = d[n/2] + 1
return
if n not in d:
length = 0
temp = n
while temp > 1:
if temp%2 == 0:
temp //= 2
else:
temp = 3*temp + 1
length += 1
if temp in d:
length += d[temp]
break
d[n] = length
d={1: 1}
for key in range(first,last):
function1(key, d)
请注意,我使用的是本地length
变量,而不是始终从d[n]
读取长度。 Python中的本地存储在C数组中,避免了对键进行散列并进行查找(可能包括散列冲突)。
我从/
(浮点除法)切换到//
(整数除法);当你感兴趣的是整数结果时,不需要处理小数点。
如果在字典中找到n/2
,我也返回。在测试成功之后测试n not in d
是没有意义的,因为我们刚刚添加了d[n]
。
词典理解完全是多余的,function1()
已经就地改变了d
,所以建立一个新的词典来取代现有的结果毫无意义。
下一步是使用您刚刚计算的temp
值序列。当您从3
开始时,您会计算其他几个值;完成后,所有这些内容都可以存储在d
中,因此您无需重新计算10
,5
,16
,{{ 1}}和8
:
4
此处def function1(n,d):
if n not in d:
length = 0
seen = []
while n > 1:
seen.append(n)
if n % 2 == 0:
n //= 2
else:
n = 3 * n + 1
length += 1
if n in d:
length += d[n]
break
for num in seen:
d[num] = length
length -= 1
需要8个步骤,但我们可以为3
存储7个,为10
存储6个等等。
我完全放弃了5
测试,if n/2 in d
循环已经处理了这种情况。由于while
块中不再需要n
,因此我完全放弃了if n not in d
并继续使用temp
。
现在整个测试只需1.75秒。
答案 1 :(得分:1)
我相信一个有用的优化(在我的MB Air上获得2.4秒,在1.3 GHz时获得Core i5,在Python 2.7.3中获得最佳3次;使用3.4.1秒,2.7秒)是为了避免“浪费” temp
的各种计算 - 保持它们可以让你非常直接地计算它们的d
值。这是我的版本......:
import time
start = time.clock()
first = 2
last = 1000000
def function1(n, d):
if n%2 == 0 and n//2 in d:
d[n] = d[n//2] + 1
if n not in d:
temp = n
intermediates = []
while temp > 1:
if temp%2 == 0:
temp //= 2
else:
temp = 3 * temp + 1
if temp in d:
d[n] = res = d[temp] + len(intermediates) + 1
for i, temp in enumerate(intermediates, 1):
d[temp] = res - i
return res
else:
intermediates.append(temp)
return d[n]
d={1: 1}
for k in range(first, last): function1(k, d)
print(time.clock() - start)
答案 2 :(得分:0)
这是Collatz conjecture。你可以查看一些关于互联网的信息,一些关于它的C或C ++代码,也许是Python。我想你会发现人们以前做过的一些有用的功能。
你也可以使用numpy模块,你可以用它制作一些公式,我认为用它会更快.Numpy是一个你可以轻松进行数学运算的模块。