ABBYYでの
就職についての記事を読んでいるときに、その問題について言及しました。
すばやく-数値のO(log N)算術演算の場合-N番目のフィボナッチ数を見つける
私はそれについて考え、O(N)の間に機能するソリューションのみが頭に浮かぶことに気付きました。 しかし、解決策は後で見つかりました。
便宜上、表記から移動します

に

。 セットにも表記法を使用します。

非負の整数

正の整数です。 事実、さまざまな数学的伝統では、多くの自然数に0が含まれる場合と含まれない場合があります。したがって、国際数学のテキストでは、これを明示的に示すことが推奨されています。
だから解決策
ナッツ[
1、p。 112 ]は、次の形式の行列IDを提供します。

身元は証明なしで与えられますが、帰納法によって非常に簡単に証明されます。
右側のマトリックスは、Qマトリックスと呼ばれることもあります。
注:

アイデンティティからそれを得る

。 つまり 計算する

行列を計算する必要があります

そして、最初の行の最初の要素(1から番号付け)を取得します。
計算以来

行列を累乗することに還元された場合、このプロセスをより詳細に検討します。
マトリックスを用意しましょう

力に引き上げられる

。 また、

2のべき乗、つまり

。

ツリーとして表すことができます:

これは以下を参照します:

。
したがって、行列を計算するには

行列を計算する必要があります

そしてそれ自体で乗算します。 計算する

あなたは同じことをする必要があります

など
明らかに、木の高さは

。
計算時間を見積もる

。 マトリックス

ある程度までは一定のサイズを持ちます。 したがって、2つの行列の任意の程度への乗算は、

。 そのような乗算はすべて実行する必要があります

。 したがって、計算の複雑さ

等しい

。
また、nが2のべき乗でない場合はどうなりますか?
ここで疑問が生じます:もしも

2のべき乗ではありませんか? 任意の自然数

は、2のべき乗である数の合計として分解できます。繰り返しは行われません(2進数から10進数に変換するたびにこれを行います)。 つまり

、
どこで

-コンクリートが何度も通過する

。 思い出すと

行列の次数である場合、次のようになります。

。
一般に、行列積は可換ではありませんが、 乗算中のオペランドの順序は重要ですが、いわゆる 順列行列の可換性が尊重されます。 マトリックス

はの順列です

、

。 したがって、乗算するときにオペランドの順序を覚えておく必要はありません。
したがって、計算アルゴリズム

以下のステップとして表すことができます。
- 分解する
セットの形式での2の累乗の合計
。 - セットのすべての要素を計算する
。 - 計算する
。
このアルゴリズムの実行時間を推定します。
最初のステップは時間内に完了します

どこで

-ビット数

。
2番目のステップは

なぜなら もう完了する必要はありません

行列を累乗します。
3番目のステップは

なぜなら もう行列の乗算を実行する必要はありません

回。
最適化
このアルゴリズムの実行時間を改善することは可能ですか? はい、できます。 2番目のステップでは、セット内の行列を計算する方法

。 私たちはそれらについてそれぞれ知っている

2のべき乗です。 ツリーのある図に戻ると、これらはすべてツリーの特定の階層にあり、大きな階層を計算するには、小さな階層を計算する必要があります。
メモ化手法を適用し、計算された行列をツリーのすべての層に保存すると、2番目のステップの作業時間を短縮できます。

アルゴリズム全体の実行時間もアップしています

。 これは、問題の状態によって必要なものです。
コード
コーディングに移りましょう。 次の2つの理由から、Pythonでアルゴリズムを実装しました。
- 擬似コードを置き換えるのに十分な表現力があります。
- 透過的な長演算があります。
これは次のとおりです。
class MatrixFibonacci:
Q = [[1, 1],
[1, 0]]
def __init__(self):
self.__memo = {}
def __multiply_matrices(self, M1, M2):
"""
( 2x2)."""
a11 = M1[0][0]*M2[0][0] + M1[0][1]*M2[1][0]
a12 = M1[0][0]*M2[0][1] + M1[0][1]*M2[1][1]
a21 = M1[1][0]*M2[0][0] + M1[1][1]*M2[1][0]
a22 = M1[1][0]*M2[0][1] + M1[1][1]*M2[1][1]
r = [[a11, a12], [a21, a22]]
return r
def __get_matrix_power(self, M, p):
""" ( p )."""
if p == 1:
return M
if p in self.__memo:
return self.__memo[p]
K = self.__get_matrix_power(M, int(p/2))
R = self.__multiply_matrices(K, K)
self.__memo[p] = R
return R
def get_number(self, n):
""" n-
( n )."""
if n == 0:
return 0
if n == 1:
return 1
powers = [int(pow(2, b))
for (b, d) in enumerate(reversed(bin(n-1)[2:])) if d == '1']
matrices = [self.__get_matrix_power(MatrixFibonacci.Q, p)
for p in powers]
while len(matrices) > 1:
M1 = matrices.pop()
M2 = matrices.pop()
R = self.__multiply_matrices(M1, M2)
matrices.append(R)
return matrices[0][0][0]
mfib = MatrixFibonacci()
for n in range(0, 128):
num = mfib.get_number(n)
print(num)
,

. :
def get_number(self, n):
if n == 0:
return 0
a = 0
b = 1
c = 1
for i in range(n-1):
c = a + b
a = b
b = c
return c
.

.
MatrixFibonacci
IterationFibonacci
(, ). 10 000

.

. :
n <tab> T1 <tab> T2
. .

, -

(c ,

64 ). , , .
. gnuplot —
.
P.S. , TeX- . , .
- . , 1. . — 3- . — .: «», 2006.