【问题标题】:Ruby beginner - need help optimising this codeRuby 初学者 - 需要帮助优化此代码
【发布时间】:2017-04-12 22:28:02
【问题描述】:

目前在学习Ruby/编程的过程中,我遇到了这个问题:

你的任务是建造一座由 n 个立方体组成的建筑物。底部的立方体的体积为n^3,上面的立方体的体积为(n-1)^3,依此类推,直到顶部的体积为1^3。 您将获得建筑物的总体积m。得到m,你能找到你必须建造的立方体数量n吗? 函数findNb(find_nb, find-nb) 的参数将是一个整数m,如果存在这样的n,则必须返回整数n,例如n^3 + (n-1)^3 + ... + 1^3 = m;如果不存在这样的n*,则必须返回-1

这是我解决这个问题的尝试:

def find_nb(m)
  (1..Float::INFINITY).each do |n|
    if (1..n).inject(0) {|sum, value| sum + value**3} == m
      return p n 
    else
      next
    end
  end
end

这似乎适用于我知道会起作用的输入,例如:

find_nb(4183059834009)
find_nb(135440716410000)
find_nb(40539911473216)

我需要帮助的领域:

  • 我不知道当没有满足等式的n 的值并因此输出-1 的输入时,我该如何理解

    find_nb(24723578342962)
    
  • 非常感谢任何有关如何使现有代码更好的提示。

【问题讨论】:

  • 答案已经涵盖了大部分要点,但我认为值得重申的是,在问题本身中寻找优化是很重要的。既然你知道n^3 + (n - 1)^3 + ... 和等于m,你就知道n^3 不能大于m(界限显然比这更严格,但它是一个简单的起点)。因此,您知道在 m 的立方根之上搜索 n 值是没有意义的。

标签: ruby algorithm optimization enumerable


【解决方案1】:

提示1:你不需要去无穷大:在某个n之后,总和将大于m,并迅速远离。

提示 2:如果找到 n,函数将永远不会到达最后一行,因为 return

提示 3:如果您到达 each 块的末尾,next 是自动的。

提示 4:立方和不需要每次都从头开始重新计算。你不是在建造一座全新的建筑,你只是在下面放了一个更大的立方体。

所以...

def find_nb(m)
  n = 1
  sum = 1
  while sum < m
    n += 1
    sum += n**3
  end
  return sum == m ? n : -1
end

编辑:这是一个功能版本,但我认为上面的普通 while 仍然更清晰(而且可能更快):

def find_nb(m)
  sum = 0
  sizes = 1.upto(Float::INFINITY)
    .lazy
    .map { |n| sum += n ** 3 }
    .take_while { |x| x <= m }
    .to_a
  sizes.last == m ? sizes.length : -1
end

【讨论】:

  • 打我吧!很好的解释,我只想补充一点,在您的sum 超过m 的任何情况下,您都可以返回-1。在 ruby​​ 中返回也是可选的,但这里更明确
  • @Anthony:“如果您的sum 超过m,您可以返回-1”:如果您检查逻辑,那正是我正在做的。只要while 还在继续,它就不会发生。
  • 是的,我们在同一页上,我的意思是在您的书面解释中(与您的代码分开),以帮助您找到答案。
【解决方案2】:

修复/改进您的代码

要修复您的代码,请在您的 if-statement 中创建另一个分支,告诉您的迭代何时返回 -1nexteach 迭代中不需要(感谢 @Amadan 指出这一点)。

请注意,最好不要从方法定义中打印任何内容。调用方法时打印。缩进和间距得到了改进。另请注意,我在变量 total 中定义立方体的总和:

def find_nb m
  (1..Float::INFINITY).each do |n|
    total = (1..n).inject(0) { |sum, value| sum + value**3 }
    if total == m
      return n 
    elsif total > m
      return -1
    end
  end
end

find_nb 4183059834009   #=> 2022
find_nb 135440716410000 #=> 4824
find_nb 40539911473216  #=> 3568
find_nb 37              #=> -1

进一步改进

如果你想使用无限循环,Ruby 有loop。像这样使用with_index

def find_nb m
  loop.with_index(1) do |_,n|
    t = (1..n).inject { |sum,i| sum + i**3 }
    if t == m
      return n            
    elsif t > m
      return -1        
    end
  end
end

find_nb 4183059834009   #=> 2022
find_nb 135440716410000 #=> 4824
find_nb 40539911473216  #=> 3568
find_nb 37              #=> -1

【讨论】:

    猜你喜欢
    • 2020-08-08
    • 2021-04-11
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多