如何在Ruby中使用递归来编写fibonacci序列?

时间:2015-04-15 06:19:51

标签: ruby recursion fibonacci ternary

我试图在Ruby中创建一个方法,如果数字包含在斐波纳契序列中,则返回true;如果不包含,则返回false。

我认为当我返回真或假时我遇到了问题。

有人可以告诉我为什么第一个代码不起作用吗?

def is_fibonacci?(num, array=[0,1])

  n = array.length - 1

  if array[n] > num
    array.include?(num) ? true : false
  end

  array << array[n] + array[n-1]
  is_fibonacci?(num, array)

end

当我运行此代码时,我收到此错误消息。

=&gt; filename.rb:36:在`include?&#39;:中断

def is_fibonacci?(num, array=[0,1])
  n = array.length - 1

  if array[n] > num
    if array.include?(num)
        return true
    else
        return false
    end
  end

  array << array[n] + array[n-1]
  is_fibonacci?(num, array)

end

第二个代码有效。

为什么我不能使用

array.include?(num) ? true : false 
代码中的

感谢您的帮助。

6 个答案:

答案 0 :(得分:2)

Shivam已经很好地回答了为什么你的第一个版本不起作用的问题。

我只想指出,没有理由将所有计算出的斐波纳契数保留在数组中。这是浪费空间,可能有点低效。因此,您可以将方法简化为:

def fibonacci?(number)
  fibos = [0, 1]
  fibos << (fibos.shift + fibos.last) while fibos.last < number
  fibos.include?(number)
end

答案 1 :(得分:1)

array.include?(num) ? true : false不起作用的原因是因为您没有return语句。将其更改为return array.include?(num) ? true : false。然而,它只会调用另一级递归算法,并最终进入堆栈深度。

作为奖励,这里是使用哈希的着名单行:

fibonacci = Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] }

p fibonacci[2]  # => 1
p fibonacci[23] # => 28657

答案 2 :(得分:1)

  

为什么我不能使用array.include?(num) ? true : false

语法上这个语句没有错,它应该可以正常工作。 (虽然在代码的上下文中可能会返回SystemStackError: stack level too deep,因为您没有返回任何值)。

以下是一个例子:

array = [0,1]
num = 1
array.include?(num) ? true : false
# => true
num = 3
array.include?(num) ? true : false
# => false

然而,这是可怕的代码。 .include?的官方文件明确指出:

  

如果给定对象存在于self中(即,如果有的话),则返回true   object == anObject),否则为false。

这意味着:

num = 1
array.include?(num)
# => true
num = 3
array.include?(num)
# => false

您再次在以下代码中重复相同的错误:

 if array.include?(num)
    return true
 else
    return false
 end

上述所有代码只能替换为一行:

return array.include?(num)

答案 3 :(得分:1)

在您的第一个版本中,块

if array[n] > num
  array.include?(num) ? true : false
end

语法正确(虽然令人讨厌),但语义对您的程序不正确,因为您不会返回结果。您可以在该语句上添加显式return,也可以使程序的其余部分成为else子句。以下版本有效,因为默认情况下Ruby返回最后一个执行语句的结果,并且只评估if / else的一个分支:

def is_fibonacci?(num, array=[0,1])
  n = array.length - 1
  if array[n] > num
    array.include?(num)
  else
    array << array[n] + array[n-1]
    is_fibonacci?(num, array)
  end
end

答案 4 :(得分:0)

使用@hirolau的哈希概念,我们可以用两行来完成。

def fib?(n)
  @fibonacci ||= Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] }
  (0..n+1).any? { |x| @fibonacci[x] == n }
end

答案 5 :(得分:0)

Fibonacci数算法可以通过两种方式完成:with和w / o recursion。递归版必须实现memoization以避免算法的指数复杂性。

变式1:

class Fibonacci
  def initialize(num)
    @num = num
    @array = [0,1]
  end

  def process
    return @num if [0,1].include?(@num)
    2.upto(@num).each do |i|
      @array[i] = @array[i-1] + @array[i-2]
    end
    @array[@num]
  end
end

变式2:

class FibonacciMemoizedRecursion
  def initialize(num)
    @num = num
    @memo = {0 => 0, 1 => 1, 2 => 1}
  end

  def process
    recursion(@num)
  end

  private

  def recursion(a)
    return @memo[a] if @memo.include?(a)
    @memo[a] = recursion(a-1) + recursion(a-2)
  end
end

为了测试我们可以使用MiniTest库:

require 'minitest/autorun'

class FibonacciTest < Minitest::Unit::TestCase
  def test_process_1
    assert_equal 0, Fibonacci.new(0).process
  end

  def test_process_2
    assert_equal 1, Fibonacci.new(1).process
  end

  def test_process_3
    assert_equal 1, Fibonacci.new(2).process
  end

  def test_process_4
    assert_equal 2, Fibonacci.new(3).process
  end

  def test_process_5
    assert_equal 3, Fibonacci.new(4).process
  end

  def test_process_6
    assert_equal 5, Fibonacci.new(5).process
  end

  def test_process_7
    assert_equal 8, Fibonacci.new(6).process
  end

  def test_process_8
    assert_equal 13, Fibonacci.new(7).process
  end
end