web-dev-qa-db-ja.com

末尾再帰フィボナッチ

O(n)でループが実行されていない再帰的なフィボナッチ関数を実装するにはどうすればよいですか?

12
Mat.S

通常、私はこのような宿題の質問への回答を投稿することに反対しますが、これまでに投稿されたものはすべて、物事を複雑にしすぎているようです。上記のコメントで述べたように、反復的に行うように、再帰を使用して問題を解決する必要があります。

反復的な解決策は次のとおりです。

def fib(n):
  a, b = 0, 1
  while n > 0:
    a, b = b, a+b
    n -= 1
  return a

同等の再帰的ソリューションは次のとおりです。

def fib(n):
  def fib_help(a, b, n):
    return fib_help(b, a+b, n-1) if n > 0 else a
  return fib_help(0, 1, n)

どちらの場合も、実際にはFまで計算することに注意してくださいn + 1、ただしFを返すn 結果として。これは、与えられた「ヒント」とうまく一致します。

時間をかけて2つのソリューションを比較し、それらが同等であることを確信していただければ幸いです。反復ソリューションを同等の再帰ソリューションに(またはその逆に)変換する方法を理解することは、開発するのに適したスキルです。

48
DaoWen

N番目のフィボナッチ数を見つけるためのScalaコード。末尾再帰の詳細については http://nerds.logdown.com/posts/1406258-n-th-fibonacci-number

object Main {
     def main(args: Array[String]) {
        println(fib(9));
        println(fib(8));
        println(fib(7));
        println(fib(6));
        println(fib(5));
        println(fib(4));
        println(fib(3));
        println(fib(2));
        println(fib(1));
        println(fib(0));
      }
      def fib(n: Int): Int = {
        def fib(n: Int, p :Int, c: Int): Int ={
          if (n == 0) return -1; // undefined
          if (n == 1) return p;
          fib(n-1, c, p + c)
        }
        fib(n, 0, 1);
      }
    }
1
Deepak Kumar

誰かがJavaScriptソリューションを探している場合:

function _fib(n, left, right) {
  switch (n) {
    case 0: return 0
    case 1: return right
    default: return _fib(n - 1, right, left + right)
  }
}

function fib(n) {
  return _fib(n, 0, 1)
}

これは、O(n)時間とO(1)スペースで、末尾呼び出しの最適化を使用して実行されます。

0
bcherny

これを線形時間で解決するには、メモ化と呼ばれる動的計画法を使用する必要があります。

メモ化を使用した疑似コードのフィボナッチのアルゴリズムは、次のようになります。

memoryMap[n]

func fib(int n)
    if (n is in memoryMap) then
        return memoryMap[n]
    if (n <= 1) then
        memoryMap[n] = n
    else
        memoryMap[n] = fib(n-1) + fib(n-2)

    return memoryMap[n]

説明すると、fib(x)を呼び出すたびに、結果がメモリマップに保存されます。後続の呼び出しごとに、fib(x)へのすべてのルックアップは無料になります。つまり、メモリコストで結果をルックアップするのにかかる時間はO(1)時間のみです。

0
831