2011-06-14 98 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(:*)