はい、あなたの洞察は正しいです。これは動的計画法と呼ばれます。これは通常、一般的なメモリ ランタイムのトレードオフです。
fibo の場合、すべてをキャッシュする必要さえありません。
[編集] 質問の著者は、フィボナッチを計算する方法ではなく、キャッシュする一般的な方法を探しているようです。この答えを得るには、ウィキペディアを検索するか、他のポスターのコードを見てください。これらの答えは、時間と記憶において直線的です。
**これは線形時間アルゴリズム O(n)、メモリ内定数 **
in OCaml:
let rec fibo n =
let rec aux = fun
| 0 -> (1,1)
| n -> let (cur, prec) = aux (n-1) in (cur+prec, cur)
let (cur,prec) = aux n in prec;;
in C++:
int fibo(int n) {
if (n == 0 ) return 1;
if (n == 1 ) return 1;
int p = fibo(0);
int c = fibo(1);
int buff = 0;
for (int i=1; i < n; ++i) {
buff = c;
c = p+c;
p = buff;
};
return c;
};
これは線形時間で実行されます。しかし、ログは実際に可能です!!! Roo のプログラムも線形ですが、かなり遅く、メモリを消費します。
これが対数アルゴリズム O(log(n)) です
対数時間アルゴリズム (はるかに高速) については、次の方法があります。u(n)、u(n-1) がわかっている場合、u(n+1)、u(n) の計算は、マトリックスの適用:
| u(n+1) | = | 1 1 | | u(n) |
| u(n) | | 1 0 | | u(n-1) |
あなたが持っているように:
| u(n) | = | 1 1 |^(n-1) | u(1) | = | 1 1 |^(n-1) | 1 |
| u(n-1) | | 1 0 | | u(0) | | 1 0 | | 1 |
行列の指数の計算は対数的に複雑です。アイデアを再帰的に実装するだけです:
M^(0) = Id
M^(2p+1) = (M^2p) * M
M^(2p) = (M^p) * (M^p) // of course don't compute M^p twice here.
それを対角化することもできます (それほど難しくありません)。黄金数とその固有値の共役が見つかり、その結果から u(n) の正確な数式が得られます。これらの固有値の累乗が含まれているため、複雑さは依然として対数になります。
Fibo は、動的計画法を説明するための例としてよく取り上げられますが、ご覧のとおり、実際には関係ありません。
@ジョン:ハッシュとは何の関係もないと思います。
@John2: マップは少し一般的だと思いませんか? フィボナッチの場合、すべてのキーが連続しているため、ベクトルが適切です。ここでも、フィボ シーケンスを計算するはるかに高速な方法があります。そこにある私のコード サンプルを参照してください。