Последовательность Фибоначчи в 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 )

Ответ 1

Попробуй это

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)

Теперь вас обрушило множество решений :)

относительно проблемы в решении ур

вы должны вернуть n если его 0 или 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

Ответ 2

Вот что я придумал, я нахожу это более прямым.

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

Ответ 3

Это не так, как вы вычисляете фибоначчи, вы создаете огромное рекурсивное дерево, которое не удастся для относительно небольших n s. Я предлагаю вам сделать что-то вроде этого:

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

Ответ 4

линейный

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)

Ответ 5

PHI = 1.6180339887498959
TAU = 0.5004471413430931

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

Вам не нужна рекурсия.

Ответ 6

Этот подход быстрый и использует запоминание:

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

Ответ 7

Рекурсия очень медленная, здесь более быстрый способ

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 => 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. по постоянному коэффициенту, ну, я не хотел быть здесь очень основательно. Но недавно я провел много исследований по числу фибоначчи, и я хочу, чтобы мои исследования были полезны для всех, кто хочет учиться ;;).

Ответ 8

Это может вам помочь.

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, " "}

Ответ 9

я думаю, это довольно легко:

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

end

Ответ 10

Попробуйте это oneliner

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

Выход: 987

Ответ 11

самый быстрый и самый маленький в линейном решении:

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

функциональный автопортрет :)

Ответ 12

Мы можем выполнять список фибо-рядов, используя алгоритм ниже

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] 

Ответ 13

Если вы хотите написать самый быстрый функционал алгоритма для fib, он не будет рекурсивным. Это один из немногих раз, когда функциональный способ написать решение медленнее. Поскольку стек повторяется, если вы используете что-то вроде

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)

Ответ 14

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 

Ответ 15

Другой подход к вычислению чисел фибоначчи, использующих преимущество memoization:

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

Ответ 16

Вот более краткое решение, которое создает таблицу поиска:

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

Кто-то спросил меня что-то подобное сегодня, но он хотел получить массив с последовательностью фибоначчи для заданного числа. Например,

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

Вот мое решение. Он не использует рекурсию tho. Еще одно решение, если вы ищете нечто подобное: P

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

Ответ 18

Вот один из них в 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)
  }
}

Ответ 19

Я думаю, что это лучший ответ, который был ответом другой должности SO, задающей аналогичный вопрос.

В принятом ответе от PriteshJ здесь используется наивная рекурсия фибоначчи, что прекрасно, но становится чрезвычайно медленным, как только вы пройдете мимо 40-го или около того элемента. Это намного быстрее, если вы кешируете /memoize предыдущие значения и передаете их, когда вы рекурсивно итерации.

Ответ 20

Это было какое-то время, но вы можете написать довольно элегантную и простую однолинейную функцию:

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

Ответ 21

Это фрагмент, который я использовал для решения проблемы программирования в 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

Присоединение к поезду Фибоначчи:

Regular:

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

еще один ;)

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}