关于ruby:试图找到最大的素因子

Trying to find largest prime factor

这来自于关于项目欧拉的第三个问题:

https://projecteuler.net/问题=3

问题:13195的主要因素是5、7、13和29。数字600851475143的最大主因子是什么?

因为这是一个谜,我不喜欢使用罐装的Ruby方法。所以这就是…

当前逻辑:num是我们要查找的质数因子。候选人是一个潜在的主要因素sqrt是num的平方根

1
until candidate >= sqrt

我从埃拉托森的筛网中借用了这个想法来寻找素数,在这里算法检查到num平方根的每个数的可除性。候选者是测试num是否有除数的数字。

1
2
3
if num % candidate == 0
...
end

目的是检查num是否可以被任何东西整除(具有因子)。如果num不能被候选者整除,那么候选者将增加1,直到until语句为真或num可以被候选者整除为止。

如果num可以被候选者整除,那么我们就知道候选者是质数,它被插入质数因子中。然后递归会测试新定义的num。

1
prime_factors << num

如果until循环为真,那么num没有除数,因此是质数。因此,它被插入到素数因子中。

问题:

问题不在于它超时了,而在于它给出了错误的答案。我的代码循环似乎超出了需要。我添加了一些日志。我不知道为什么,但我认为这和递归部分有关。诚然,我从不在代码中使用递归,我想用它来扩展我的技能集。所以递归在概念上对我来说是模糊的。任何阅读也会有帮助。

应该发生什么:主因子=[2,2,19]Prime_Factors.Last=19

实际发生的情况:主因子=[2,2,19,19,38]Prime_Factors.Last=38

整个代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def largest_prime_factor(num,prime_factors)
 puts"beg fx: num: #{num},  prime_factors: #{prime_factors}
 candidate = 2
 sqrt = Math.sqrt(num)
 loop_count = 0
 until candidate >= sqrt
   if num % candidate == 0
     num = num / candidate
     prime_factors << candidate
     largest_prime_factor(num,prime_factors)
   end
   candidate += 1
   loop_count +=1
 end
   puts"
outside loop: candidate >= sqrt is #{candidate >= sqrt} num: #{num}, prime_factors: #{prime_factors}, candidate: #{candidate}, sqrt: #{sqrt}, loop: #{loop_count}"
   gets
 prime_factors << num
 prime_factors.last
end


因此,正如您所建议的,问题似乎是递归逻辑。

仅仅因为你递归地调用一个函数并不意味着"父"停止工作——他只是坐着等待"子"完成,然后继续工作。这就是这种"循环过度"发生的地方。代码实际上不是循环过度,而是结束。

您可以在Puts语句中看到这一点。注意,在循环停止后,sqrt会增加,因为脚本现在正在运行父代码,而不是在递归块(子)完成之后。

为了解决这个问题,我做了两件事:1。创建一个布尔值,指示代码块已经历递归。如果是,运行此代码,否则…做点别的。2。如果候选者不是2,则递增2。这将跳过测试除2之外的所有偶数。没有必要测试其他偶数,因为它不是素数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def largest_prime_factor(num,prime_factors,recursive)
  candidate = 2
  until candidate >= Math.sqrt(num)
    recursive = false
    if num % candidate == 0
      num = num / candidate
      recursive = true
      prime_factors << candidate
      largest_prime_factor(num,prime_factors,recursive)
    end
    break if recursive
    candidate == 2 ? candidate += 1 : candidate += 2
  end
  prime_factors << num unless recursive
  prime_factors.last
end