決定的なforループを使用してフィボナッチ数列のn番目の項を見つけることは可能ですか?


7

私はJohn Zelle著の本の「Introduction to Computer Science」を使用しており、第3章(数値による計算)の最後に、おそらく決定的なforループを使用しているフィボナッチ数列のn番目の項を見つけるように求められます。構造はまだ導入されています。

これは可能ですか?思いつく限りのことを試しました。

**私はifステートメントなどを使用してそれを解決する方法を知っています。しかし、この本はまだ決定構造をカバーしていませんが、それでも私は(ユーザーから与えられた)n番目の用語を見つけるように求めてきます。これがこれまでカバーしてきたことなので、 "for"ループを使用してこれを行う方法を知っているとしか推測できません。


1
"definitive for loop"はどういう意味ですか?
Keith Thompson

基本的にカウントされたループ。例えば、私は、入力としてn番目の項を取り、範囲(入力)に私のために言う:
qzxt

if条件式をforループに移動してステートメントを削除することもできますが、それは完全に役に立たないハック、IMHOです。
toniedzwiedz

それで、私は狂っていません、そして、条件文なしでこれを行うことは本当にありませんか?
qzxt

@qzxtは無効な入力をキャッチしたい場合には違います。
toniedzwiedz

回答:


11

それが第3章だけの場合は、著者が動的プログラミングをカバーしていたのではないかと思いますが、forループを使用して nth フィボナッチ数、 Fn

定義を思い出してください、

Fn={0n=01n=1Fn1+Fn2otherwise

Pythonで定義されている再帰関数を使用して、これを単純に計算できます。

def fib(n):
    if n < 2:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

ただし、同じ副問題を何度も再計算することにより、この関数は計算に指数時間を必要とします(下図を参照)。 フィブツリー

ただし、修正はあります。動的プログラミングを使用して「よりスマートな」再帰を実行し、以前の結果を維持できます。この方法では、再計算する必要はありませんFi。関数呼び出し「ツリー」はリストに折りたたまれ、計算されますFn 「ボトムアップ」から。 fib2

def fib2(n):
    if n < 2:
        return n
    else:
        if not results[n]:
            results[n] = fib2(n - 1) + fib2(n - 2)
        return results[n]

今私たちは持っています O(n) 計算する時間アルゴリズム Fn、しかし気づいたら、 O(n) 追加スペース(アレイごとに1つのスポット) Fi)。これを削減することができますO(1) それぞれのために追加のスペース Fi 他の2つのフィボナッチ数のみが必要です。 Fi1 そして Fi2

def fib3(n):
    if n < 2:
        return n
    f_0 = 0
    f_1 = 1
    f_n = 0
    for _ in range(n - 1):
        f_n = f_0 + f_1
        f_0 = f_1
        f_1 = f_n


    return f_n

2
うわー、素晴らしい答え!これをプリミティブな再帰と互換性のある形式にすること、つまり一般的な定義でカウントダウンすることは、ni(カウントダウン)ループ内。
ラファエル

10

n番目のフィボナッチ数が見つかるまで繰り返すforループのみを使用する必要がある場合は、次のようなものを使用できます。

int fib(int n)
{
    int p = 0;
    int c = 1;
    int r = 0; // The result is initialized to 0 (undefined). 
    for (int i = 0; i < n; i++)
    {
        r = p + c; // Produce next number in the sequence.
        p = c;     // Save previous number.
        c = r;     // Save current number.
    }

    return r;
}

注意

上記のソリューションでは、フィボナッチ数列は1 1 2 3 5 8 13 ...であり、nの範囲は1、2、3、...であると想定しています。これらの仮定の下では、n <1のフィボナッチ数は存在しないためです。 、関数はn <1に対して0を返し、入力パラメーターが範囲外であることを示します(以下のコメントのトムの提案を参照)。


0の出力は0である必要があります。それ以外の場合は、良い、単純で簡潔な答えになります。
toniedzwiedz

カウント方法によって異なりますが、実際にはn <1の場合、fibは未定義である必要があります。それとも、0が未定義であることを意味するため、fib(n)はすべてのn <1で0を返す必要がありますか?
Giorgio

それは本当です、それは依存します。0を含める場合、出力は0になります。それを除外する場合、関数は無効な入力を示す特別な値を返す必要があります。これは負の数に対しても実行する必要があります...しかし、OPは条件式を受け入れません。スローする例外がはるかに少ないので、私はそれがそれで良い方法だと思います。
toniedzwiedz

2
@ジョルジオ数学的には、フィボナッチ数列は完全に明確に定義されています n<0; シーケンスを逆方向に実行したり、反転させたりするのを妨げるものは何もありませんfn+1=fn+fn1 取得するため fn1=fn+1fn -または、定義 gn=fngn+1=gn1gn
Steven Stadnicki 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.