web-dev-qa-db-ja.com

Ruby(再帰)のフィボナッチ数列

次の関数を実装しようとしていますが、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 )
17
Maputo

これを試して

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)

これで、多くのソリューションが攻撃されました:)

urソリューションの問題について

0または1の場合、nを返す必要があります

add最後と次ではなく、最後の2つの数字

新しい修正バージョン

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
41
Pritesh Jain

これは私が思いついたものですが、これはもっと簡単です。

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

これはフィボナッチの計算方法ではなく、比較的小さなnsで失敗する巨大な再帰ツリーを作成しています。私はあなたがこのようなことをすることを勧めます:

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) }
11
Victor Moroz

線形

_module Fib
  def self.compute(index)
    first, second = 0, 1
    index.times do
      first, second = second, first + second
    end
    first
  end
end
_

再帰的キャッシングあり

_module Fib
  @@mem = {}
  def self.compute(index)
    return index if index <= 1

    @@mem[index] ||= compute(index-1) + compute(index-2)
  end
end
_

閉鎖

_module Fib
  def self.compute(index)
    f = fibonacci
    index.times { f.call }
    f.call
  end

  def self.fibonacci
    first, second = 1, 0
    Proc.new {
      first, second = second, first + second
      first
    }
  end
end
_

Fib.compute(256)を呼び出しても、これらのソリューションはシステムをクラッシュさせません。

9
Dudo

このアプローチは高速で、メモ化を利用します。

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

9
Bijan
PHI = 1.6180339887498959
TAU = 0.5004471413430931

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

再帰は必要ありません。

7
iblue

再帰は非常に遅いですが、これはより速い方法です

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)ですが、行列のべき乗を使用できます。これは私の実装の1つですが、Java => 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;
}

それでも、カラツバ乗算を使用すると、両方の行列exp。高速ダブリングははるかに速くなりますが、高速ダブリングはマトリックスexpをビートします。一定の要因で、まあここまで徹底したくありませんでした。しかし、私は最近、フィボナッチ数に関する多くの研究を行ったので、私の研究を、学習したい人なら誰でも利用できるようにしたいと思っています。;).

6
user1621170

これはあなたを助けるかもしれません。

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, " "}
4
Peter Prabu

このワンライナーをお試しください

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

出力:987

4
Yaron Lambers

これはかなり簡単だと思います:

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

end
4
mizan rahman

以下のアルゴリズムを使用してリスト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] 
4

最速かつ最小のインラインソリューション:

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

機能的な自撮りパターン:)

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

これにより、aにシリーズが入力されます。 (max <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 
2
Santhosh

以下は、ルックアップテーブルを作成するより簡潔なソリューションです。

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}
2

メモ化を利用してフィボナッチ数を計算する別のアプローチ:

$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メソッドの呼び出し回数が大幅に削減されます。

1

以下はScalaの1つです。

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)
  }
}
1
farhany

Fibの最速関数アルゴリズムを記述したい場合、再帰的ではありません。これは、ソリューションを作成するための機能的な方法が遅い数回のうちの1つです。あなたが何かを使う場合、スタックは自己を繰り返すので

fibonacci( n - 1 ) + fibonacci( n - 2 ) 

最終的にn-1とn-2は同じ数を作成するため、計算で繰り返しが行われます。これへの最速の方法は、繰り返しです

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)
1
Stuart G

これは、URIオンラインジャッジでプログラミングの課題を解決するために使用したスニペットです。

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
1
vhbsouza

久しぶりですが、かなりエレガントでシンプルな1行の関数を記述できます。

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

今日誰かが私に似たようなことを尋ねましたが、彼は与えられた数のフィボナッチ数列を持つ配列を得たいと思っていました。例えば、

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...

これが私の解決策です。それは再帰を使用していません。同様の何かを探しているなら、もう1つの解決策:P

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

さらに別の;)

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}
1
Mike Belyakov

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
1
shilovk

私は これが最良の答えです だと思います。これは、別のSO投稿からの同様の質問をした投稿からの応答でした。

ここでPriteshJから受け入れられた答えは、単純なフィボナッチ再帰を使用していますが、これは問題ありませんが、40番目の要素を超えると非常に遅くなります。以前の値をキャッシュ/メモして、再帰的に反復しながら渡すと、はるかに高速になります。

1
Batkins

フィボナッチ列車に参加する:

レギュラー:

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
1
Olian04