2011-06-14 155 views
0

我是新来的Ruby,并认为这将是学会解决在项目欧拉的问题更多的好方法。了解Ruby的逻辑运算符

这就是我想出了使用暴力的问题5:

#What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20? 
end_point = 1_000_000_000 
start_point = 2_520 
(start_point..end_point).each do |number| 
    flag = true 
    (2..20).each do |divisor| 
    flag = flag & (number % divisor) == 0 ? true : false 
    end 
    print number.to_s + "\n" if flag 
end 

它运行很长一段时间,并没有给出答案。

然后我用同样的逻辑来写C++程序做同样的任务:

#include<iostream> 

using namespace std; 

int main() 
{ 
    unsigned long int solution = 2520; 
    while(1) 
    { 
    bool flag = true; 
    for(int divisor=2;divisor<=20;divisor++) 
    { 
     if(solution % divisor == 0) 
     flag = flag & true; 
     else{ 
     flag = false; 
     break; 
     } 
    } 
    if(flag == true){ 
     cout<<solution<<endl; 
     break; 
    } 
    solution++; 
    } 
    return 0; 
} 

这一次给了我正确的解决方案并运行几乎没有第二个。执行时间并不关心我,因为Ruby被解释和C++编译,但Ruby在返回正确答案方面的失败让我感到惊讶。我认为这可能是因为我试图编写C++ Ruby风格,而不是实际的Ruby方式。

我在这里做错了什么?

回答

2

注:我还没有运行,下面无论是提出的解决方案来完成 - 他们仍然需要很长的时间 - 所以正确性不能保证!

,你更新flag该生产线的问题。您正在使用&(按位与),而不是&&(布尔和)。

在其他问题,&==更高的运算符优先级,让你的行被解释为(因为? true : false是多余的):

flag = (flag & (number % divisor)) == 0 

现在看来true & some_integertrue,这是不== 0,因此flag始终设置为false

相反,你想:

flag = flag && (number % divisor == 0) 

,或者更简洁和Rubyish:

flag &&= number % divisor == 0 

另一种解决办法是要做到:

i = 1 
while true 
    break unless (2..20).any? {|d| i % d != 0} 
    i+=1 
end 
puts i 
+0

您的替代解决方案正是我正在寻找, 人们如何编写比我能够在红宝石上更美丽的代码,这不是太好了吗?我想知道我该如何真正学习这种红宝石方式。 – nikhil 2011-06-14 09:27:18

+0

你能告诉我&&和'和'之间的区别吗?最初我使用'和',因为这不起作用,我试过&。 – nikhil 2011-06-14 09:31:38

+1

不客气。我认为这里的相关思想是Ruby喜欢直接用集合来做事情;也就是说,在Enumerable上调用隐式循环方法比在显式循环内容上更鲁莽。顺便说一下,这两种方法都给出了正确的答案,但我的速度更快(因为任何一种方法一旦失败就会短路)。 – Chowlett 2011-06-14 09:32:58

3

我其实解决了这个问题无需为它编写程序。 这是我使用的逻辑:

写下所有质数小于20(目标)。

[2, 3, 5, 7, 11, 13, 17, 19]

对于每个素数,它提升到对于其比目标(20)更小的最大功率。

2**4 * 3**2 * 5 * 7 * 11 * 13 * 17 * 19

对于做编程方式使用埃拉托色尼的筛 - http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes算法遍历素数。对于列表中的每个素数,找出获得小于目标数的最大功率(20)。你可以找到使用这个公式的力量:(Math.log(target)/Math.log(i)).floor

假设你得到的素数的数组:使用此nums = [2, 3, 5, 7, 11, 13, 17, 19]

然后你就可以得到答案很容易:

nums.map {|i| i**((Math.log(target)/Math.log(i)).floor)}.inject(:*)