Python出人意料的性能:蛮力vs字典(Collatz序列)
在这个问题上,字典可能比暴力慢吗?Python出人意料的性能:蛮力vs字典(Collatz序列),python,performance,dictionary,brute-force,Python,Performance,Dictionary,Brute Force,在这个问题上,字典可能比暴力慢吗? 问题(来源): 为正整数集定义以下迭代序列: n→ n/2(n为偶数) n→ 3n+1(n为奇数) 使用上述规则并从13开始,我们生成以下序列: 13→ 40→ 20→ 10→ 5.→ 16→ 8.→ 4.→ 2.→ 1 可以看出,这个序列(从13开始到1结束)包含10个术语。虽然还没有被证明(科拉兹问题),但人们认为所有的起始数字都以1结束 100万以下的哪个起始编号产生的链最长? 注:一旦链开始,条款允许超过一百万 代码[暴力]: 我从一个蛮力程序开始,
- 问题(来源):
为正整数集定义以下迭代序列:
n→ n/2(n为偶数)
使用上述规则并从13开始,我们生成以下序列:n→ 3n+1(n为奇数)
可以看出,这个序列(从13开始到1结束)包含10个术语。虽然还没有被证明(科拉兹问题),但人们认为所有的起始数字都以1结束 100万以下的哪个起始编号产生的链最长? 注:一旦链开始,条款允许超过一百万13→ 40→ 20→ 10→ 5.→ 16→ 8.→ 4.→ 2.→ 1
- 代码[暴力]:
我从一个蛮力程序开始,该程序从1到1000000取每个数字,并打印找到的最长链
完成大约需要30秒。
# number from 1 to 1000000 num = 0 # longest chain here maxLength = 0 # number that produce the longest chain result = 0 while num < 1000000: num += 1 k = num # count the current chain pieces i = 0 while k > 1: i += 1 if k%2 == 0: k /= 2 else: k = k*3 + 1 if maxLength < i: maxLength = i result = num print result
# number from 1 to 1000000 num = 0 # longest chain here maxLength = 0 # number that produce the longest chain result = 0 dictionary = {} while num < 1000000: num += 1 k = num i = 0 while k > 1: # if it processed the number before, it use the shortcut if str(k) in dictionary.keys(): i += dictionary[str(k)] break i += 1 if k%2 == 0: k /= 2 else: k = k*3 + 1 # add new shortcut if not (str(num) in dictionary.keys()): dictionary[str(num)] = i if maxLength < i: maxLength = i result = num print result
然后我说:“时间太多了!让我们实现字典吧!”#从1到1000000的数字 num=0 #这里最长的链条 maxLength=0 #产生最长链的编号 结果=0 当num<1000000时: num+=1 k=num #计算当前链件的数量 i=0 当k>1时: i+=1 如果k%2==0: k/=2 其他: k=k*3+1 如果maxLength
- 代码[字典]:
对于字典,每次链结束时,链的起始编号和链件编号都存储在字典中,因此当它多次找到相同的编号时,可以使用字典中存储的与此编号关联的值
5分钟后,我停止了它。
# number from 1 to 1000000 num = 0 # longest chain here maxLength = 0 # number that produce the longest chain result = 0 while num < 1000000: num += 1 k = num # count the current chain pieces i = 0 while k > 1: i += 1 if k%2 == 0: k /= 2 else: k = k*3 + 1 if maxLength < i: maxLength = i result = num print result
# number from 1 to 1000000 num = 0 # longest chain here maxLength = 0 # number that produce the longest chain result = 0 dictionary = {} while num < 1000000: num += 1 k = num i = 0 while k > 1: # if it processed the number before, it use the shortcut if str(k) in dictionary.keys(): i += dictionary[str(k)] break i += 1 if k%2 == 0: k /= 2 else: k = k*3 + 1 # add new shortcut if not (str(num) in dictionary.keys()): dictionary[str(num)] = i if maxLength < i: maxLength = i result = num print result
#从1到1000000的数字 num=0 #这里最长的链条 maxLength=0 #产生最长链的编号 结果=0 字典={} 当num<1000000时: num+=1 k=num i=0 当k>1时: #如果之前处理过该号码,则使用快捷方式 如果dictionary.keys()中的str(k): i+=字典[str(k)] 打破 i+=1 如果k%2==0: k/=2 其他: k=k*3+1 #添加新快捷方式 如果不是(dictionary.keys()中的str(num)): 字典[str(num)]=i 如果maxLength
if str(k) in dictionary.keys():
# ^^^^^
这很糟糕。这将把一组键变成一个列表
!并扫描该线路(在python3中,它是一个发生器,但几乎同样糟糕)
你可以说
if str(k) in dictionary:
这样做是正确的,用O(1)代替O(n)
此外,在python中,将内容转换为字符串以用作
dict
中的键是不必要的。数字很好,所以你真的可以说:k
无论你现在说什么str(k)
,只要你纠正一下,现在只需要2.5秒!谢谢