Ruby 初学者 - 需要帮助优化此代码

Ruby beginner - need help optimising this code

目前在学习Ruby/programming的过程中,总的来说,遇到了这个问题:

Your task is to construct a building which will be a pile of n cubes. The cube at the bottom will have a volume of n^3, the cube above will have volume of (n-1)^3 and so on until the top which will have a volume of 1^3. You are given the total volume m of the building. Being given m can you find the number n of cubes you will have to build? The parameter of the function findNb(find_nb, find-nb) will be an integer m and you have to return the integer n such as n^3 + (n-1)^3 + ... + 1^3 = m if such a n exists or -1 if there is no such n*.

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

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)

我需要帮助的领域:

提示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

Fixing/Improving 你的代码

要修复您的代码,请在 if-statement 中创建另一个分支,告诉您的迭代何时 return -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