Ruby中的Fibonacci序列(递归)

时间:2012-08-29 13:04:47

标签: ruby recursion fibonacci

我试图实现以下功能,但它一直给我stack level too deep (SystemStackError)错误。

任何想法可能是什么问题?

def fibonacci( n )
    [ n ] if ( 0..1 ).include? n
    ( fibonacci( n - 1 ) + fibonacci( n - 2 ) ) if n > 1
end

puts fibonacci( 5 )

26 个答案:

答案 0 :(得分:38)

试试这个

def fibonacci( n )
  return  n  if ( 0..1 ).include? n
  ( fibonacci( n - 1 ) + fibonacci( n - 2 ) )
end
puts fibonacci( 5 )
# => 5

检查此帖子Fibonacci One-Liner

以及更多.. https://web.archive.org/web/20120427224512/http://en.literateprograms.org/Fibonacci_numbers_(Ruby)

你现在受到许多解决方案的轰炸:)

关于你的解决方案中的问题

如果n0

,您应该返回1

add最后两个数字不是最后一个

  

新修改版

def fibonacci( n )
    return  n  if n <= 1 
    fibonacci( n - 1 ) + fibonacci( n - 2 )
end 
puts fibonacci( 10 )
# => 55
  

一个班轮

def fibonacci(n)
   n <= 1 ? n :  fibonacci( n - 1 ) + fibonacci( n - 2 ) 
end
puts fibonacci( 10 )
# => 55

答案 1 :(得分:16)

这是我想出的东西,我发现这更直接。

def fib(n)
  n.times.each_with_object([0,1]) { |num, obj| obj << obj[-2] + obj[-1] }
end
fib(10)

答案 2 :(得分:11)

这不是你计算斐波纳契的方法,你创建了一个巨大的递归树,对于相对较小的n来说,它会失败。我建议你做这样的事情:

def fib_r(a, b, n)
  n == 0 ? a : fib_r(b, a + b, n - 1)
end

def fib(n)
  fib_r(0, 1, n)
end

p (0..100).map{ |n| fib(n) }

答案 3 :(得分:8)

<强>线性

module Fib
  def self.compute(index)
    first = 0
    second = 1
    index.times do
      third = first + second
      first = second
      second = third
    end
    first
  end
end
使用缓存

递归

module Fib
  @@mem = {}
  def self.compute(index)
    if index <= 1
      return index
    else
      @@mem[index] ||= compute(index-1) + compute(index-2)
    end
  end
end

如果您拨打Fib.compute(256)

,这些解决方案都不会导致系统崩溃

答案 4 :(得分:7)

这种方法很快并且使用了memoization:

fib = Hash.new {|hash, key| hash[key] = key < 2 ? key : hash[key-1] + hash[key-2] }

fib[123] # => 22698374052006863956975682

如果你想知道这个哈希初始化是如何工作的,请阅读:

https://ruby-doc.org/core/Hash.html#method-c-new

答案 5 :(得分:7)

PHI = 1.6180339887498959
TAU = 0.5004471413430931

def fibonacci(n)
  (PHI**n + TAU).to_i
end

你不需要递归。

答案 6 :(得分:5)

递归非常慢,这是一种更快的方式

a = []; a[0] = 1; a[1] = 1
i = 1
while i < 1000000
    a[i+1] = (a[i] + a[i-1])%1000000007
    i += 1
end

puts a[n]    

它是O(1),但你可以使用矩阵求幂,这是我的一个实现,但它在java =&gt; http://pastebin.com/DgbekCJM,但矩阵exp。的O(8logn)。这是一个更快的算法,称为快速加倍。这是一个快速加倍的java实现。

class FD {

    static int mod = 1000000007;

    static long fastDoubling(int n) {
        if(n <= 2) return 1;
        int k = n/2;
        long a = fastDoubling(k+1);
        long b = fastDoubling(k);
        if(n%2 == 1) return (a*a + b*b)%mod;
        else return (b*(2*a - b))%mod;
}

然而,使用karatsuba乘法,两个矩阵exp。并且快速加倍变得快得多,但快速加倍节拍矩阵exp。通过一个恒定的因素,我不想在这里非常彻底。但我最近做了很多关于斐波纳契数的研究,我希望我的研究对任何愿意学习的人都有用;)。

答案 7 :(得分:3)

这可能会对你有帮助。

def fib_upto(max)
  i1, i2 = 1, 1
  while i1 <= max
    yield i1
    i1, i2 = i2, i1+i2
  end
end

fib_upto(5) {|f| print f, " "}

答案 8 :(得分:3)

我认为这很简单:

def fibo(n) a=0 b=1 for i in 0..n c=a+b print "#{c} " a=b b=c end

end

答案 9 :(得分:3)

试试这个oneliner

def fib (n)
    n == 0 || n == 1 ? n : fib(n-2) + fib(n-1)
end
print fib(16)

输出:987

答案 10 :(得分:2)

最快和最小的线解决方案:

fiby = ->(n, prev, i, count, selfy) {
  i < count ? (selfy.call n + prev, n, i + 1, count, selfy) : (puts n)
}
fiby.call 0, 1, 0, 1000, fiby

功能性自拍图案:)

答案 11 :(得分:2)

我们可以使用以下算法执行列表fibo系列

def fibo(n)
  n <= 2 ? 1 : fibo(n-1) + fibo(n-2)
end

我们可以生成如下的系列

p (1..10).map{|x| fibo(x)}

以下是此

的输出
=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] 

答案 12 :(得分:1)

今天有人问我类似的东西,但他想得到一个给定数字的斐波那契序列数组。例如,

fibo(5)  => [0, 1, 1, 2, 3, 5]
fibo(8)  => [0, 1, 1, 2, 3, 5, 8]
fibo(13) => [0, 1, 1, 2, 3, 5, 8, 13]
# And so on...

这是我的解决方案。它没有使用递归。如果你正在寻找类似的东西,还有一个解决方案:P

def fibo(n)
  seed = [0, 1]
  n.zero? ? [0] : seed.each{|i| i + seed[-1] > n ? seed : seed.push(i + seed[-1])}
end

答案 13 :(得分:1)

1)示例,其中最大元素<100

def fibonachi_to(max_value)
  fib = [0, 1]
  loop do
    value = fib[-1] + fib[-2]
    break if value >= max_value
    fib << value
  end
  fib
end

puts fibonachi_to(100)

输出:

0
1
1
2
3
5
8
13
21
34
55
89

2)示例,其中10个元素

def fibonachi_of(numbers)
  fib = [0, 1]
  (2..numbers-1).each { fib << fib[-1] + fib[-2] }
  fib
end

puts fibonachi_of(10)

输出:

0
1
1
2
3
5
8
13
21
34

答案 14 :(得分:1)

我认为是this is the best answer,这是另一个SO帖子提出类似问题的回复。

来自PriteshJ的接受回答使用了天真的斐波纳契递归,这很好,但是一旦超过第40个左右的元素就变得非常慢。如果你缓存/记忆以前的值并在递归迭代时传递它们会快得多。

答案 15 :(得分:1)

这是Scala中的一个:

object Fib {
  def fib(n: Int) {
    var a = 1: Int
    var b = 0: Int
    var i = 0: Int
    var f = 0: Int
    while(i < n) {
      println(s"f(${i+1}) -> $f")
      f = a+b
      a = b
      b = f
      i += 1
    }
  }

  def main(args: Array[String]) {
    fib(10)
  }
}

答案 16 :(得分:1)

这是一个构建查询表的更简洁的解决方案:

fibonacci = Hash.new do |hash, key|
  if key <= 1
    hash[key] = key
  else
    hash[key] = hash[key - 1] + hash[key - 2]
  end
end

fibonacci[10]
# => 55 
fibonacci
# => {1=>1, 0=>0, 2=>1, 3=>2, 4=>3, 5=>5, 6=>8, 7=>13, 8=>21, 9=>34, 10=>55}

答案 17 :(得分:1)

利用记忆力计算斐波那契数的另一种方法:

$FIB_ARRAY = [0,1]
def fib(n)
  return n if $FIB_ARRAY.include? n
  ($FIB_ARRAY[n-1] ||= fib(n-1)) + ($FIB_ARRAY[n-2] ||= fib(n-2))
end

这确保每个斐波那契数只被计算一次,大大减少了对fib方法的调用次数。

答案 18 :(得分:1)

a = [1, 1]
while(a.length < max) do a << a.last(2).inject(:+) end

这将填充a系列。 (当max&lt; 2)

时,你必须考虑这种情况

如果只需要第n个元素,您可以使用Hash.new

fib = Hash.new {|hsh, i| hsh[i] = fib[i-2] + fib[i-1]}.update(0 => 0, 1 => 1)

fib[10]
# => 55 

答案 19 :(得分:1)

如果你想为fib编写最快的功能算法,它将不会递归。这是编写解决方案的功能方式较少的几次之一。因为如果使用像

这样的东西,堆栈会重复自我
fibonacci( n - 1 ) + fibonacci( n - 2 ) 

最终n-1和n-2将创建相同的数字,因此将在计算中进行重复。最快的方法是iteratvily

def fib(num)
# first 5 in the sequence 0,1,1,2,3
fib1 = 1 #3
fib2 = 2 #4
i = 5 #start at 5 or 4 depending on wheather you want to include 0 as the first number
while i <= num
    temp = fib2
    fib2 = fib2 + fib1
    fib1 = temp
    i += 1
end
p fib2
end
fib(500)

答案 20 :(得分:0)

已经有一段时间了,但你可以编写一个相当优雅和简单的单行函数:

def fib(n)
  n > 1 ? fib(n-1) + fib(n-2) : n
end

答案 21 :(得分:0)

这是我用来解决URI Online Judge编程挑战的片段,希望它有所帮助。

def fib(n)
  if n == 1
    puts 0
  else
    fib = [0,1]
    (n-2).times do
      fib << fib[-1] + fib[-2]
    end
    puts fib.join(' ')
  end
end

fib(45)

输出

# => 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465 14930352 24157817 39088169 63245986 102334155 165580141 267914296 433494437 701408733

答案 22 :(得分:0)

加入斐波纳契火车:

正则:

def fib(num)
  return num if (num < 2) else fib(num-1) + fib(num-2)
end

使用缓存:

module Fib
  @fibs = [0,1]
  def self.calc(num)
    return num if (num < 2) else @fibs[num] ||= self.calc(num-1) + self.calc(num-2)
  end
end

答案 23 :(得分:0)

另一个;)

def fib(n)
  f = Math.sqrt(5)
  ((((1+f)/2)**n - ((1-f)/2)**n)/f).to_i
end

也将方便地添加一些缓存

def fibonacci
  @fibonacci ||= Hash.new {|h,k| h[k] = fib k }
end

所以我们将能够得到它

fibonacci[3]  #=> 2
fibonacci[10] #=> 55
fibonacci[40] #=> 102334155
fibonacci     #=> {3=>2, 10=>55, 40=>102334155}

答案 24 :(得分:0)

一个很好的 Ruby 简介 Fiber -

def fibs x, y
  Fiber.new do
    while true do
      Fiber.yield x
      x, y = y, x + y
    end
  end
end

上面我们创建了一个无限的 fibs 数字流,以非常有效的方式计算。一个不是简单的 puts 无限流,所以我们必须编写一个小函数来从我们的流中收集有限数量的项目,take -

def take t, n
  r = []
  while n > 0 do
    n -= 1
    r << t.resume
  end
  r
end

最后让我们看看序列中的前 100 个数字,从 01 开始 -

puts (take (fibs 0, 1), 100)
0
1
1
2
3
5
8
13
21
34
55
.
.
.
31940434634990099905
51680708854858323072
83621143489848422977
135301852344706746049
218922995834555169026

答案 25 :(得分:0)

这个使用记忆化和递归:

def fib(num, memo={})
  return num if num <= 1

  if memo[num]
    return memo[num]
  else
    memo[num] = fib(num - 2, memo) + fib(num - 1, memo)
  end
end