项目Euler 1:找到1000或以下3或5的所有倍数的总和

我试图用Project Euler解决Ruby中的数学问题。 这是我尝试过的第一个:

如果我们列出10以下的所有自然数是3或5的倍数,我们得到3,5,6和9.这些倍数的总和是23。

求出1000以下3或5的所有倍数的总和。

请帮我改进我的代码。

total = 0 (0...1000).each do |i| total += i if (i%3 == 0 || i%5 == 0) end puts total 

更快(恒定时间)答案:

 def sum_multiples(multiple, to) n = (to-1) / multiple n * (n+1) / 2 * multiple end irb(main):001:0> sum_multiples(3, 10) + sum_multiples(5, 10) - sum_multiples(15, 10) => 23 irb(main):002:0> sum_multiples(3, 1000) + sum_multiples(5, 1000) - sum_multiples(15, 1000) => 233168 

为什么这样做? sum_multiples出多个multiple的总和,但不包括(它依赖于整数除法)。 首先计算出被加总的倍数( n )的数量,然后将1..n = n(n + 1)/ 2之和的标准公式乘以multiple 。 使用这个,我们可以将3和5的倍数加在一起。我们必须不要忘记有些数字是3和5的倍数,所以我们减去15(3 * 5)的倍数。

虽然你的答案对于这个问题的约束来说足够快(它应该在现代硬件上运行大约1毫秒),但是更快的解决方案,例如我提供的解决方案,会产生非常大的数字。

好吧,首先你可以跳过大约666个数字,从3开始,递增3.这样,你只考虑3的倍数。然后做第二个循环,从5开始,递增5.这里,你需要检查对于3的倍数(或跳过每第3个生成的数字,因为它们恰好是3的倍数),因为它们之前已被求和。

这将检查~500个数字,大约是所需数字的一半。

或者,您可以看看是否可以计算出总和的封闭forms(原则上,将数字从1加到楼层(最大值,N)加起来,乘以N,对你的Ns(3和5)执行此操作,但是你必须减去重复计算的数字,但这实际上减去了N = 15的相同数字。

这是我的方法,找到i(1,333)3 * k(3,6,9 …)和(1,200)5 * k。

  • 计算所有可被3整除的数并计算总和
  • 将所有可整除的数量计算为5并计算总和
  • 被15整除的数字应该算作一个

3 *(1 + 2 + 3 + … + 333)+ 5 *(1 + 2 + 3 ..) – 15 *(1 + 2 …)你可以用n *(n + 1)表示)/ 2并且它是O(1)时间但我用循环实现我的代码

这是我的第一个Ruby代码 🙂

 total = 0 (0...334).each do |i| total += i*3 end (0...200).each do |i| total += i*5 if (i % 3 != 0) end puts total 

这是演示

 puts (0..1000).select {|n| n%3==0 || n%5==0}.inject(0) {|s,n| s+=n} 

完全按照问题中的说明完成此操作的另一种方法:

 ((1..(999/3)).map {|x| x*3} | (1..(999/5)).map {|x| x*5}).reduce(&:+) 

但是marcog的恒定时间答案是更好的方式。

在一行

 (0..1000).to_a.reject!{|a| (a%3 != 0 && a%5 != 0) }.inject(0) { |s,v| s += v } 

如下所述,以下内容不正确

 (0...1000).to_a.reject!{|a| (a%3 == 0 || a%5 == 0) }.inject(0) { |s,v| s += v } 
 (1..999).select { |num| (num % 3 == 0) || (num % 5 == 0) }.reduce(:+) 

这里我们num从一个范围中选择可被3或5整除的所有num 。结果是一个Array

然后我们可以链接#reduce:+#reduce数组中的所有元素。

一内胆:

 (3...1000).find_all {|n| n % 3 == 0 || n % 5 == 0}.inject(:+) 

Ruby非常优雅!

我真的很喜欢marcog的回答。

但无论如何这里的方法使用了类似Eratosthenes的筛子 。

 divisors = [3, 5] limit = 1000 can_be_divided = Array.new(limit + 1, false) divisors.each do |d| i = d while i < limit can_be_divided[i] = true i += d end end result = 0 can_be_divided.each_with_index { |v, i| result += i if v } 

我的解决方案使用O(N)存储器和鲁棒O(D * N),其中N是极限,D是除数。

它不会与优雅的数学解决方案竞争,但也许你会发现它很有趣。

我猜的好处是,随着除数的增加,数学解决方案将更难计算,因为你需要使用分母。 在[3,5]的情况下,它很容易 - 唯一的分母是15.但是[3,5,7,11,13]呢? 您将不得不编写能够找到所有共同点的代码,并且它不会那么容易阅读。

 public class Sample { public static void main(final String args[]) { // Find the sum of all the multiples of 3 or 5 below 1000. int temp = 0; for (int i = 1; i <= 1000; i++) { if ((i % 3 == 0) && (i % 5 == 0)) { System.out.println(i); // add them temp = temp + i; } } System.out.println(temp); } } 

一个简单的公式可以是3 +倍数的倍数,是5的倍数 – 数字是3的倍数,5不是10

所以total_no = 3 + 2-0 = 5(3,5,6,9,10)

total_no =(无/ 3)+(无/ 5) – (无/ 15)