由100盏灯想到的(二)

 本系列的第一篇:

http://www.cnblogs.com/dhf327/p/4773672.html

100盏灯的问题,上次我们算是基本解决了,不管算法上是否够优化,至少我们已经在可接受的时间得到了答案。

但是最后还留了一道题,亲们,你们是不是已经想出来了?

一,上次的题目

上一篇给出了python求一个正整数的所有的因数的方法,这个方法目前工作正常,求单个正整数的所有因数速度上也没有任何问题。

但是结合上一篇最后的题目,有心的同学一下子就看出问题来了,1到10的12次方,假设求每个数的所有因数需要1毫秒,整个循环总共需要多长时间?(考虑到后期的数字比较大,前期的数字比较小,这个1毫秒还是比较乐观的时间)

 python可以快速计算一下:

1 print(1000000000000/1000/60/60/24/365)

结果是 >31.7  这个数的单位应该是吧,我的老天,不是在逗我玩吧。这个时间任谁也接受不了,这个QQ群咱们不加了?

显然,就算我们使用并行算法,在可接受的时间内,仍不能得到正确的结果。也许可以用集群来处理,又好像大炮打蚊子了。

此时需要算法优化了。

二,再谈算法优化

当常现方式不能解决的时候,我们需要一种新的思路来解决这个问题,因为这基本是个纯数学问题,而我的数字功底一般,那就请出万能的搜索引擎吧,找到两个相关的定理可以用到。

约数个数定理,约数和定理。这里的约数也就是因数。百度百科的解释如下:

对于一个大于1正整数n可以分解质因数:n=p1^a1*p2^a2*p3^a3*…*pk^ak,
则由约数个数定理可知n的正约数有(a₁+1)(a₂+1)(a₃+1)…(ak+1)个,
那么n的(a₁+1)(a₂+1)(a₃+1)…(ak+1)个正约数的和为
f(n)=(p1^0+p1^1+p1^2+…p1^a1)*(p2^0+p2^1+p2^2+…p2^a2)*…*(pk^0+pk^1+pk^2+…pk^ak)

如10=2^1*5^1;  则10的因数个数为 (1+1)*(1+1)=4个,因数和为(2^0+2^1)+(5^0+5^1)=18

上面定理的内容没有提到,一般的p1<p2<p3...

证明可以自己去找资料,总之这个内容我们是可以拿来用了。

如果用这个定理,似乎可以解决我们的问题了,让我们试试看。

三,分解质因数

每个数要分解质因数,也就是质数的因数,忘记质数定义的同学请自行百度,

假设我们有从2开始的连续的质数有序序列,我们可以很快的计算出一个数分解质数的结果。

m=[2,3,5,7,11,13,17,19,...]

假设对n进行分解质因数,那么就是从2开始,如果能整除,就用整除后的值再除以2,如果除不尽的时候,就除以下一个值3,依次类推,直到分解完毕。

这就是有名的短路算法。

让我们来比较一下,上一篇中我们求所有的因数的算法,可以真正求出一个正整数的所有的因数,而现在利用这个公式,我们可以不用求出所有的因数,就能直接对所有的因数进行求和,似乎是更快了一些。

实际上,上一篇中的算法不依赖任何其他的东西,只是计算量比较而已,虽然只是从2到n的平方根,但这其中的每个数都要参与运算,计算量很大。

此时新的短路算法,看起来比较快,但是还有很重要的一点,他需要一个质数的序列!

问题似乎变复杂了。

未完待续)

原文地址:https://www.cnblogs.com/dhf327/p/4779115.html