寻找600851475143的最大素数因子

时间:2013-05-12 17:56:58

标签: ruby-on-rails ruby algorithm math

我正在尝试使用程序来查找最大的素数因子600851475143.这是针对Project Euler的:http://projecteuler.net/problem=3

我首先尝试使用此代码:

    #Ruby solution for http://projecteuler.net/problem=2
    #Prepared by Richard Wilson (Senjai)

    #We'll keep to our functional style of approaching these problems.
    def gen_prime_factors(num) # generate the prime factors of num and return them in an array
      result = []
      2.upto(num-1) do |i| #ASSUMPTION: num > 3
        #test if num is evenly divisable by i, if so add it to the result.
        result.push i if num % i == 0
        puts "Prime factor found: #{i}" # get some status updates so we know there wasn't a crash
      end
      result #Implicit return
    end

#Print the largest prime factor of 600851475143. This will always be the last value in the array so:
puts gen_prime_factors(600851475143).last #this might take a while

这对于小数字来说非常好,但对于大数字来说,这需要很长时间(并且需要大量内存)。

现在我刚刚上了大学的微积分,但是我很生疏,从那时起就没有跟上我的数学。

我不想直接回答,但我想指出资源或告诉我需要学习什么才能实现我在程序中看到的一些算法。

1 个答案:

答案 0 :(得分:9)

您的解决方案存在一些问题。首先,你永远不会测试i是否为素数,因此你只能找到大数的最大因子,而不是最大的素因子。您可以使用一个Ruby库,只需require 'prime',并且可以为您的条件添加&& i.prime?

这将解决你的程序中的不准确性,但它仍然会很慢而且昂贵(事实上,它现在会更加昂贵)。你可以做的一个显而易见的事情就是设置result = i而不是result.push i,因为你最终只关心你找到的最后一个i,没有理由维护所有素数的列表因素。

然而,即便如此,它仍然非常缓慢。正确的程序应该几乎立即完成。关键是每次找到一个主要因素时缩小你测试的数量。如果你找到了你的大数字的素数因子p,那么你就不需要再一直测试到大数字了。您想要测试的“新”大号是在尽可能多次将p与大数字分开后留下的内容:

big_number = big_number/p**n

其中n是最大的整数,右侧仍然是整数。实际上,您无需明确查找此n,只需按p除以直到您停止获取整数。

最后,作为一个 SPOILER ,我在下面提供了一个解决方案,但如果您仍想自己解决这个问题,可以选择忽略它。

require 'prime'

max = 600851475143; test = 3

while (max >= test) do
  if (test.prime? && (max % test == 0))
    best = test
    max = max / test
  else
    test = test + 2
  end
end

puts "Here's your number: #{best}"

练习:证明可以从test.prime?条件中删除if。 [提示:关于任何数字的最小(非1)除数,你能怎么说?]
练习:如果我们改为使用max = 600851475145,此算法会很慢。对于max的任何一个值,如何快速改进? [提示:手动找出600851475145的主要因子分解;它很容易做到,它会清楚说明为什么当前算法对于这个数字来说很慢]