对于其中一个项目Euler问题,这是一个(非常糟糕的)解决方案。问题是找到10_001st素数。下面的代码可以实现,但运行需要8分钟。你能解释为什么会这样,以及如何优化它?
primes = []
number = 2.0
until primes[10000] != nil
if (2..(number - 1)).any? do |n|
number % n == 0
end == false
primes << number
end
number = number + 1.0
end
puts primes[10000]
答案 0 :(得分:7)
主要发现的一些简单优化:
首先将2推入素数列表,然后检查3是否为素数。 (这消除了为数字0到2编写特殊情况代码的需要)
您只需要检查主要候选资格的奇数。 (或者,如果你开始添加2/3/5并检查7,你只需要在执行%6后检查1或5的数字。或者......你明白了)
您只需要看看您当前的候选人x
是否可以被截至sqrt(x
)的因子整除 - 因为任何高于sqrt(x)
的因子将x除以下面的数字sqrt(x)
,您已经检查了所有这些内容。
您只需检查主要列表中的数字,而不是所有数字,对于x
的除数 - 因为所有复合数字都可以被素数整除。例如,81是9 * 9 - 但9 * 9是3 * 3 * 9,9是复合的,所以当你检查它时你会发现它是一个素数。因此你永远不需要测试9是否是一个因素等每个复合因素。
有非常优化的,加速的主要查找功能(请参阅Sieve of Atkin开始),但这些是很容易想到的常见优化。
答案 1 :(得分:1)
你真的要检查这个数字是否除以以前的所有数字?只检查您已发现的较小素数。另外,为什么使用整数完全正常的浮点数?
修改强>
一些可能的变化(不是最好的算法,可以改进):
primes = [2, 3, 5]
num = 7
until primes[10000]
is_prime = true
i = 0
sqrtnum = Math.sqrt(num).ceil
while (n=primes[i+=1]) <= sqrtnum
if num % n == 0
is_prime = false
break
end
end
if is_prime
primes << num
end
num += 2
end
puts primes[10000]
在我的电脑上(1000个素数):
Yours:
real 0m3.300s
user 0m3.284s
sys 0m0.000s
Mine:
real 0m0.045s
user 0m0.040s
sys 0m0.004s