【问题标题】:Euler 23 in Ruby红宝石中的欧拉 23
【发布时间】:2017-12-14 23:20:07
【问题描述】:

好的。我认为我有正确的想法找到 Euler #23 的解决方案(关于找到所有不能表示为两个丰富数之和的数字之和的方法)。

但是,很明显,我的一种方法太该死的野蛮了。 你如何解除暴力并使其发挥作用?

sum_of_two_abunds?(num, array) 是有问题的方法。我已经尝试预先排除某些数字,但它仍然需要很长时间,我什至不确定它是否给出了正确的答案。

def divsum(number)
  divsum = 1
  (2..Math.sqrt(number)).each {|i| divsum += i + number/i if number % i == 0}
  divsum -= Math.sqrt(number) if Math.sqrt(number).integer?
  divsum 
end

def is_abundant?(num)
  return true if divsum(num) > num
  return false
end

def get_abundants(uptonum) 
  abundants = (12..uptonum).select {|int| is_abundant?(int)}
end

def sum_of_two_abunds?(num, array)
  #abundant, and can be made from adding two abundant numbers.
  array.each do |abun1|
    array.each do |abun2|
      current = abun1+abun2

      break if current > num
      return true if current == num
    end
  end

  return false
end

def non_abundant_sum
  ceiling = 28123
  sum = (1..23).inject(:+) + (24..ceiling).select{|i| i < 945 && i % 2 != 0}.inject(:+)
  numeri = (24..ceiling).to_a
  numeri.delete_if {|i| i < 945 && i % 2 != 0}
  numeri.delete_if {|i| i % 100 == 0}
  abundants = get_abundants(ceiling)
  numeri.each {|numerus| sum += numerus if sum_of_two_abunds?(numerus, abundants) == false}
  return sum
end


start_time = Time.now

puts non_abundant_sum

#Not enough numbers getting excluded from the total. 
duration = Time.now - start_time

puts "Took #{duration} s "

【问题讨论】:

  • 如何编辑我的帖子以修复我的代码块?你的格式化工具很神秘。
  • 我帮忙了。要输入代码块,只需将代码缩进 4 个空格(或使用编辑器中的{} 按钮为您输入)。还要记得缩进 Ruby 代码 2 个空格。
  • “我什至不确定它给出了正确的答案” --- 那你为什么不写一些测试用例呢?
  • 您的优化尝试只会让这变得更加复杂。你最好摆脱它们。
  • 另外,这与您的问题完全无关(祝您好运),但在is_abundant?(num) 方法中,您基本上是“如果条件为真则返回真,否则返回假”。对于这种类型的事情,你可以只返回条件本身的评估......

标签: ruby loops


【解决方案1】:

解决方案 1

加快速度的一种简单方法是加快您的sum_of_two_abunds? 方法:

def sum_of_two_abunds?(num, array)
  array.each do |abun1|
    array.each do |abun2|
      current = abun1+abun2

      break if current > num
      return true if current == num
    end
  end

  return false
end

而不是那个内部循环,只需询问数组是否包含num - abun1

def sum_of_two_abunds?(num, array)
  array.each do |abun1|
    return true if array.include?(num - abun1)
  end
  false
end

这已经比您的 Ruby 代码更快了,因为它更简单并且运行更快的 C 代码。此外,既然这个想法很明确,您可以利用数组已排序的事实并使用二进制搜索搜索num - abun1

def sum_of_two_abunds?(num, array)
  array.each do |abun1|
    return true if array.bsearch { |x| num - abun1 <=> x }
  end
  false
end

然后制作 Rubyish:

def sum_of_two_abunds?(num, array)
  array.any? do |abun1|
    array.bsearch { |x| num - abun1 <=> x }
  end
end

现在你可以摆脱你自己的特殊情况优化并修复你不正确的divsum(例如声称divsum(4)5......你真的应该与一个不尝试的幼稚实现进行比较任何平方根优化)。

然后它应该会在一分钟内完成(在我的电脑上大约需要 11 秒)。

解决方案 2

或者你可以完全抛弃sum_of_two_abunds?,只创建两个丰富的所有和并取消它们对总和的贡献:

def non_abundant_sum
  ceiling = 28123
  abundants = get_abundants(ceiling)
  numeri = (0..ceiling).to_a
  abundants.each { |a| abundants.each { |b| numeri[a + b] = 0 } }
  numeri.compact.sum
end

在我的电脑上运行大约需要 3 秒。

【讨论】:

  • 谢谢,这似乎奏效了。似乎出于某种莫名其妙的原因,4 的平方根没有被视为一个整数。所以我把它改成检查平方根与零的模数。
  • @AaronGodhard 好吧,integer? 是关于对象类型,而不是关于值:ruby-doc.org/core-2.4.2/Numeric.html#method-i-integer-3F 你说“似乎”有效。您是否尚未将其提交给 Project Euler 以确认?顺便说一句,请考虑一下:stackoverflow.com/help/someone-answers(也适用于您之前的问题。)
猜你喜欢
  • 2015-09-28
  • 1970-01-01
  • 1970-01-01
  • 2019-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-09
相关资源
最近更新 更多