Lychrel数字

时间:2011-07-21 23:42:19

标签: ruby numbers

首先,对于那些不了解(或忘记)Lychrel数字的人,这里有来自维基百科的条目:http://en.wikipedia.org/wiki/Lychrel_number

我想在0到10_000的范围内实现Lychrel数字检测器。这是我的解决方案:

class Integer

  # Return a reversed integer number, e.g.:
  # 
  #   1632.reverse #=> 2361
  #
  def reverse
    self.to_s.reverse.to_i
  end

  # Check, whether given number
  # is the Lychrel number or not.
  #
  def lychrel?(depth=30)
    if depth == 0
      return true
    elsif self == self.reverse and depth != 30 # [1]
      return false
    end
    # In case both statements are false, try
    # recursive "reverse and add" again.
    (self + self.reverse).lychrel?(depth-1)
  end
end

puts (0..10000).find_all(&:lychrel?)

此代码的问题是深度值[1]。所以,基本上,depth是一个值,它定义了我们需要多少次进行迭代过程,当然,当前的数字实际上是一个Lychrel数。默认值是30次迭代,但我想添加更多的纬度,因此程序员可以通过方法的参数指定自己的深度。 30次迭代非常适合我需要的小范围,但如果我想覆盖所有自然数,我必须更敏捷。

由于递归,它在Integer#lychrel?中占有一席之地,我不能敏捷。如果我向lychrel?提供了一个参数,那么由于[1]语句就不会有任何变化。

所以,我的问题听起来像这样:“我如何重构我的方法,所以它会正确接受参数?”。

3 个答案:

答案 0 :(得分:2)

您目前拥有的内容称为tail recursion。这通常可以重写为循环来消除递归调用并消除堆栈空间不足的风险。尝试更像这样的东西:

def lychrel?(depth=30)
    val = self
    first_iteration = true

    while depth > 0 do
        # Return false if the number has become a palindrome,
        #   but allow a palindrome as input
        if first_iteration
            first_iteration = false
        else
            if val == val.reverse
                return false
        end

        # Perform next iteration
        val = (val + val.reverse)
        depth = depth - 1
    end
    return true
  end

我没有在这台机器上安装Ruby,所以我无法验证这是否100%正确,但你明白了。另外,我假设and depth != 30位的目的是允许将回文提供为输入而不立即返回false

通过循环,您可以使用状态变量first_iteration来跟踪是否需要进行val == val.reverse检查。使用递归解决方案,作用域限制会阻止您轻松跟踪(您必须添加另一个函数参数并依次将状态变量传递给每个递归调用)。

答案 1 :(得分:1)

更干净,更像红宝石的解决方案:

class Integer

  def reverse
    self.to_s.reverse.to_i
  end

  def lychrel?(depth=50)
    n = self
    depth.times do |i|
      r = n.reverse
      return false if i > 0 and n == r
      n += r
    end
    true
  end

end

puts (0...10000).find_all(&:lychrel?) #=> 249 numbers

答案 2 :(得分:0)

bta的解决方案有一些更正:

class Integer

  def reverse
    self.to_s.reverse.to_i
  end

  def lychrel?(depth=30)
    this = self
    first_iteration = true

    begin
      if first_iteration
        first_iteration = false
      elsif this == this.reverse
        return false
      end

      this += this.reverse
      depth -= 1
    end while depth > 0

    return true
  end
end

puts (1..10000).find_all { |num| num.lychrel?(255) }

不是那么快,但它确实有效:

code/practice/ruby% time ruby lychrel.rb > /dev/null 
ruby lychrel.rb > /dev/null  1.14s user 0.00s system 99% cpu 1.150 total