马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
今天我们继续来看“欧拉计划”的第3题:求600851475143的最大因子。
解这题之前,我们先来看几种求质数的方法。为什么要知道求质数的方法呢?因为任何合数的因子都是由质数构成的,我们只有先求得最大质数,才能进行判定是否是这个合数的因子。
方法1:暴力穷举
比如要求n之内的所有质数,我们只需要从n-1开始,依次往下测试,如果i不能被任何>1且<=i-1的数整除的话,那么i就是质数。这个是最基本的方法,但是也是最慢的方法,尤其对于数量级比较大的数,几乎就算不出来了。
方法2:有条件穷举
虽然也是穷举,但是我们需要对测试的范围进行限定,比如我们可以直接从i**0.5开始往下测试,而不用从i-1开始,原因可以自己思考一下,很容易理解。其次,质数除2以外都是奇数,所以大于2的偶数都可以跳过不需要考虑了,这样又可以减少非常多的候选数了(其实3的倍数也可以筛选掉)。def gen_primes(n):
primes = [2,3,5]
for i in range(7,n,2):
if i % 3 == 0: continue
flag = True
for j in range(5, int(i**0.5+1), 2):
if i % j == 0:
flag = False
break
if flag:
primes.append(i)
return primes
方法3:标记法
方法2的条件穷举速度上已经快了很多,但是还有更快的。标记法的逻辑是先建立全数列,然后按等差数列批量运算,例如先把除2以外的2的倍数的数列全部标记出来,再把除3以外的3的倍数全部标记出来,由于4(2的倍数)已经标记了,再把除5以外的5的倍数全部标记出来。。。依次类推,最后未被标记的数就是质数,原因也很容易理解吧。
由于,标记法是批量运算,所以速度比一个一个数字去判断又要快上许多。
结合numpy数组的话,速度可以再上一个台阶,求100万以内的质数列表,也只需1s以内。import numpy as np
def gen_primes(n):
primes = np.ones(n, dtype='int8')
for i in range(2,int(n**0.5+1)):
if primes[i]:
primes[i*i::i] = 0
return np.nonzero(primes)[0][2:]
方法4:直接调用第三方库algorithms
algorithms库包含了非常多实用的数学工具,这部分以后会单独讲解。今天我们就先直接调用它,虽然速度不见得比我们用标记法算得快,但好处是你不需要自己去编写函数了,只要会调用就好。from algorithms.math.sieve_atkin import atkin
print(atkin(1000000))
有了那么多方法,再来计算这道题目就易如反掌了。
首先我们看一下,我们最大需要生成多大的质数列表,600851475143**0.5=775146... 我们只需取到775147即可。然后依次从质数列表中取质数(从大往小取)与600851475143取模,如果能整除,则这个数就是600851475143的最大因子。
一行代码输出:from algorithms.math.sieve_atkin import atkin
print([prime for prime in atkin(775147)[::-1] if 600851475143 % prime == 0][0])
如果我们要追求速度的话,1s以内就可以出答案了。import numpy as np
def gen_primes(n):
primes = np.ones(n, dtype='int8')
for i in range(2,int(n**0.5+1)):
if primes[i]:
primes[i*i::i] = 0
return np.nonzero(primes)[0][2:]
for prime in gen_primes(775147)[::-1]:
if 600851475143 % prime == 0:
print(prime)
break
你学会了吗? |