1

挑战在于找到满足以下foo条件的最小整数:

foo % 1..20 == 0

我目前的尝试是蛮力

until foo % 1.upto(20) == 0 do
    foo++
end

这会输出错误unexpected keyword end。但是,如果我不将end关键字放入 irb 代码将永远不会运行,因为该块没有关闭。

我做了一个空的测试用例来看看我的错误在哪里

until foo % 1.upto(20) == 0 do
end

这会引发一个新错误:enumerator can't be coerced to a fixnum. 我想这意味着您不能直接在一个范围内执行模数并期望整个范围内都有一个简洁的布尔结果。但我不知道从这里去哪里。

我的第一次尝试不是蛮力,而是倾向于尝试更有效/优雅/切中要害的东西,如下所示:

foo = 1
1.upto(20) {|bar| foo *= bar unless foo % i == 0}

给出了错误的答案。我不明白为什么,但我也对为什么感兴趣

foo = 1
20.downto(1) {|bar| foo *= bar unless foo % i == 0}

输出不同的答案。

编辑:我会使用 for 循环(我在 ActionScript 中进行编程时弄湿了我的脚),但它们在 ruby​​ 中无法正常工作。

4

4 回答 4

3

您的第一个解决方案是错误的,因为1.upto(20)它是enumerator,即本质上是值 1 到 20 的迭代器,并且它不能用作模数或与另一个数字进行比较的数字,因为它本身不是数字。

你真的需要两个“循环”:

foo = 1
foo += 1 until (1..20).all? { |i| foo % i == 0 }

第一个循环是until,然后all?是另一个循环,因为它确保块 ( { |i| foo % i == 0 }) 对于调用它的范围内的每个元素都是正确的 ( (1..20))。请注意,我使用的是单行“向后”语法(也适用于if, unless, while, ...)——以上等价于:

foo = 1
until (1..20).all? { |i| foo % i == 0 } do
  foo += 1
end
# foo => 232792560

此外,这是非常低效的,Euler 项目通常涉及比编程更多的数学,并且非暴力解决方案可能会涉及更多的数学,但速度要快得多。

于 2012-05-18T02:37:48.937 回答
2

试试这个:

until 1.upto(20).reject{|i| foo % i == 0 }.empty? do
  foo += 1
end
于 2012-05-18T02:34:08.047 回答
2

我知道这不是直接的 OP 问题,但这更容易实现:

puts (1..20).reduce(:lcm)

它是如此简单,以这种方式解决它似乎不公平,但这正是为什么 Ruby 是我选择 Project Euler 的语言的原因。

另请参阅此问题

于 2013-05-16T18:48:44.037 回答
0

如果这是我,我会定义一个函数来测试条件:

def mod_test(num)
  test = (1..20).map {|i| num % i == 0}
  test.all? # all are true
end

然后循环尝试不同的值:

foo = 20
until mod_test(foo) do
  foo += 20
end

(感谢Dylan+= 20加速。)

我敢肯定,有一种聪明的方法可以使用 的知识foo % 10 == 0来暗示foo % 5 == 0and ,并且只对andfoo % 2 == 0之间的素数执行测试,甚至可能使用该信息直接构造数字——但我的代码运行得足够快。120

于 2012-05-18T02:41:40.757 回答