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

时间:2011-01-03 18:53:51

标签: ruby algorithm math

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

  

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

     

求出3的所有倍数之和   或者低于1000。

请帮我改进我的代码。

total = 0

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

puts total

11 个答案:

答案 0 :(得分:24)

快得多(恒定时间)回答:

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的倍数之和,但不包括to(它依赖于整数除法)。它首先计算出求和的倍数(n),然后将1..n = n(n + 1)/ 2之和的标准公式乘以multiple。使用这个,我们可以将3和5的倍数加在一起。我们必须不要忘记有些数字是的两倍 3和5,所以我们减去15的倍数(3 * 5) )。

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

答案 1 :(得分:2)

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

  • 计算所有可被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

这里是demo

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:0)

完全按照问题所述的另一种方法:

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

但是marcog的常时答案是更好的方式。

答案 5 :(得分:0)

在一行

(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 }

答案 6 :(得分:0)

(1..999).select { |num| (num % 3 == 0) || (num % 5 == 0) }.reduce(:+)

我们#select来自可以被3或5整除的所有num范围。结果是Array

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

答案 7 :(得分:0)

单线:

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

Ruby很优雅!

答案 8 :(得分:0)

我真的很喜欢marcog的答案。

但是无论如何,这里的方法使用的是类似sieve of 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]呢?您将必须编写能够找到所有常见分母的代码,而且阅读起来也不容易。

答案 9 :(得分:-1)

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);
   }
}

答案 10 :(得分:-4)

一个简单的公式可以是3 +数的倍数,是5的倍数 - 数字是3和5的倍数 无= 10

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

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