Gibt es einen Algorithmus zur Berechnung der n-ten Fibonacci-Zahl in sublinearer Zeit?
Gibt es einen Algorithmus zur Berechnung der n-ten Fibonacci-Zahl in sublinearer Zeit?
Antworten:
Die n
th Fibonacci-Zahl ist gegeben durch
f(n) = Floor(phi^n / sqrt(5) + 1/2)
wo
phi = (1 + sqrt(5)) / 2
Unter der Annahme , dass die primitiven mathematischen Operationen ( +
, -
, *
und /
) sind O(1)
Sie dieses Ergebnis können Sie die berechnen n
th Fibonacci - Zahl in der O(log n)
Zeit ( O(log n)
wegen der Potenzierung in der Formel).
In C #:
static double inverseSqrt5 = 1 / Math.Sqrt(5);
static double phi = (1 + Math.Sqrt(5)) / 2;
/* should use
const double inverseSqrt5 = 0.44721359549995793928183473374626
const double phi = 1.6180339887498948482045868343656
*/
static int Fibonacci(int n) {
return (int)Math.Floor(Math.Pow(phi, n) * inverseSqrt5 + 0.5);
}
phi^n / sqrt(5) + 1/2
wo phi = (1 + sqrt(5)) / 2
. Das ist ein Fakt. Zweitens verstehe ich den Punkt, den andere über die Länge der Antwort machen, O(n)
aber ich habe meiner Antwort eine Bemerkung hinzugefügt, unter der Annahme, dass die primitiven mathematischen Operationen eine konstante Zeit benötigen (ich weiß, dass dies nicht der Fall ist, wenn Sie die Eingaben nicht gebunden haben). Mein Punkt ist, dass wir die n-te Fibonacci-Zahl in O(log n)
arithmetischen Operationen finden können.
Aus Pillsys Verweis auf die Matrixexponentiation folgt, so dass für die Matrix
M = [1 1] [1 0]
dann
fib ( n ) = M n 1,2
Das Erhöhen von Matrizen auf Potenzen durch wiederholte Multiplikation ist nicht sehr effizient.
Zwei Ansätze zur Matrixexponentiation sind Teilen und Erobern, was M n in O ( ln n ) Schritten ergibt , oder Eigenwertzerlegung, die zeitlich konstant ist, aber aufgrund der begrenzten Gleitkommapräzision Fehler verursachen kann.
Wenn Sie einen exakten Wert wünschen, der größer ist als die Genauigkeit Ihrer Gleitkommaimplementierung, müssen Sie den O (ln n) -Ansatz verwenden, der auf dieser Beziehung basiert:
M n = ( M n / 2 ) 2, wenn n gerade ist = M · M n -1, wenn n ungerade ist
Die Eigenwertzerlegung auf M findet zwei Matrizen U und Λ, so dass Λ diagonal und ist
M = U Λ U -1 M n = ( U Λ U -1 ) n = U Λ U -1 U Λ U -1 U Λ U -1 ... n-mal = U Λ Λ Λ ... U -1 = U Λ n U -1Das Erhöhen der Diagonalmatrix Λ auf die n- te Potenz ist eine einfache Sache, bei der jedes Element in Λ auf die n - te Potenz angehoben wird. Dies ergibt eine O (1) -Methode zum Erhöhen von M auf die n- te Potenz. Es ist jedoch unwahrscheinlich, dass die Werte in Λ Ganzzahlen sind, sodass ein Fehler auftritt.
Definieren Sie Λ für unsere 2x2-Matrix als
Λ = [λ 1 0] = [0 λ 2 ]
Um jedes λ zu finden , lösen wir
| M - λ I | = 0
was gibt
| M - λ I | = -λ (1 - λ) - 1 λ² - λ - 1 = 0
mit der quadratischen Formel
λ = (-b ± √ (b² - 4ac)) / 2a = (1 ± √5) / 2 {λ 1 , λ 2 } = {Φ, 1-Φ} wobei Φ = (1 + √5) / 2
Wenn Sie Jasons Antwort gelesen haben, können Sie sehen, wohin das führen wird.
Auflösen nach den Eigenvektoren X 1 und X 2 :
wenn X 1 = [ X 1,1 , X 1,2 ] M . X 1 1 = λ 1 X 1 X 1,1 + X 1,2 = λ 1 X 1,1 X 1,1 = λ 1 X 1,2 => X 1 = [Φ, 1] X 2 = [1-Φ, 1]
Diese Vektoren ergeben U :
U = [ X 1,1 , X 2,2 ] [ X 1,1 , X 2,2 ] = [Φ, 1-Φ] [1, 1]
U invertieren mit
A = [ab] [cd] => A -1 = (1 / | A |) [d -b] [-ca]
also ist U -1 gegeben durch
U -1 = (1 / (Φ - (1 - Φ)) [1 Φ-1] [-1 Φ] U -1 = (√5) -1 [1 Φ-1] [-1 Φ]
Gesundheitsüberprüfung:
UΛU -1 = (√5) -1 [Φ 1-Φ]. [Φ 0]. [1 Φ-1] [1 1] [0 1-Φ] [-1 Φ] sei Ψ = 1-Φ, der andere Eigenwert als Φ ist eine Wurzel von λ²-λ-1 = 0 also -ΨΦ = Φ²-Φ = 1 und Ψ + Φ = 1 UΛU -1 = (√5) -1 [Φ Φ]. [Φ 0]. [1 -Ψ] [1 1] [0 Ψ] [-1 Φ] = (√5) -1 [Φ Φ]. [Φ -ΨΦ] [1 1] [-Ψ ΨΦ] = (√5) -1 [Φ Φ]. [Φ 1] [1 1] [-Ψ -1] = (√5) -1 [Φ²-Ψ² Φ-Ψ] [Φ-Ψ 0] = [Φ + Ψ 1] [1 0] = [1 1] [1 0] = M.
Der Sanity Check gilt also.
Jetzt haben wir alles, was wir brauchen, um M n 1,2 zu berechnen :
M n = U Λ n U -1 = (√5) -1 [Φ Φ]. [Φ n 0]. [1 -Ψ] [1 1] [0 Ψ n ] [-1 Φ] = (√5) -1 [Φ Φ]. [Φ n -ΨΦ n ] [1 1] [-Ψ n Ψ n Φ] = (√5) -1 [Φ Φ]. [Φ n Φ n -1 ] [1 1] [-Ψ n -Ψ n -1 ] als ΨΦ = -1 = (√5) -1 [Φ n + 1 - Ψ n + 1 Φ n - Ψ n ] [Φ n -Ψ n Φ n -1 -Ψ n -1 ]
damit
fib ( n ) = M n 1,2 = (Φ n - (1 - Φ) n ) / √5
Was mit der an anderer Stelle angegebenen Formel übereinstimmt.
Sie können es aus einer Wiederholungsrelation ableiten, aber beim Engineering-Computing und der Simulation ist die Berechnung der Eigenwerte und Eigenvektoren großer Matrizen eine wichtige Aktivität, da sie Stabilität und Harmonische von Gleichungssystemen bietet und es ermöglicht, Matrizen effizient auf hohe Leistungen anzuheben.
Wenn Sie die genaue Zahl wollen (die eher ein "Bignum" als ein Int / Float ist), dann fürchte ich das
Es ist unmöglich!
Wie oben angegeben, lautet die Formel für Fibonacci-Zahlen:
fib n = floor (phi n / √5 + 1 / 2 )
fib n ~ = phi n / √5
Wie viele Ziffern gibt es fib n
?
numDigits (fib n) = log (fib n) = log (phi n / √5) = log phi n - log √5 = n * log phi - log √5
numDigits (fib n) = n * const + const
es ist O ( n )
Da das angeforderte Ergebnis O ( n ) ist, kann es nicht in weniger als O ( n ) berechnet werden.
Wenn Sie nur die unteren Ziffern der Antwort wünschen, können Sie mit der Matrix-Exponentiationsmethode in sublinearer Zeit berechnen.
O(n*log n)
für die vergleichsbasierte Sortierung einer Folge von n
Zahlen, bei denen jede Zahl O(log n)
Ziffern hat?
Eine der Übungen in SICP befasst sich mit dieser Frage , die hier beschrieben wird .
Im imperativen Stil würde das Programm ungefähr so aussehen
Funktion Fib ( Anzahl ) a ← 1 b ← 0 p ← 0 q ← 1 Während Zählung > 0 Do Wenn Even ( Zählung ) Dann p ← p ² + q ² q ← 2 pq + q ² Zahl ← Zählung ÷ 2 Else a ← bq + aq + ap b ← bp + aq Zahl ← Zahl - 1 End If End While Return b End Function
twisted
Framework).
if even(count)
ist korrekt. Die Sequenz beginnt mit Null (nullte Fibonacci-Zahl ist Null): 0,1,1,2,3,5,8,13, ...
Sie können dies tun, indem Sie auch eine Matrix von Ganzzahlen potenzieren. Wenn Sie die Matrix haben
/ 1 1 \
M = | |
\ 1 0 /
dann (M^n)[1, 2]
wird gleich der n
th Fibonacci-Zahl sein, wenn []
es sich um einen Matrixindex und eine Matrixexponentiation ^
handelt. Für eine Matrix mit fester Größe kann die Exponentiation zu einer positiven Integralleistung in O (log n) -Zeit auf die gleiche Weise wie bei reellen Zahlen erfolgen.
BEARBEITEN: Abhängig von der Art der gewünschten Antwort können Sie möglicherweise mit einem Algorithmus mit konstanter Zeit davonkommen. Wie die anderen Formeln zeigen, n
wächst die th Fibonacci-Zahl exponentiell mit n
. Selbst bei 64-Bit-Ganzzahlen ohne Vorzeichen benötigen Sie nur eine Nachschlagetabelle mit 94 Einträgen, um den gesamten Bereich abzudecken.
ZWEITE BEARBEITUNG: Das erste Exponential der Matrix mit einer Eigendekomposition entspricht genau der folgenden Lösung von JDunkerly. Die Eigenwerte dieser Matrix sind (1 + sqrt(5))/2
und (1 - sqrt(5))/2
.
Wikipedia hat eine geschlossene Lösung http://en.wikipedia.org/wiki/Fibonacci_number
Oder in c #:
public static int Fibonacci(int N)
{
double sqrt5 = Math.Sqrt(5);
double phi = (1 + sqrt5) / 2.0;
double fn = (Math.Pow(phi, N) - Math.Pow(1 - phi, N)) / sqrt5;
return (int)fn;
}
|1 - phi|^n / sqrt(5) < 1/2
when n
eine nichtnegative Ganzzahl ist.
Für wirklich große funktioniert diese rekursive Funktion. Es werden die folgenden Gleichungen verwendet:
F(2n-1) = F(n-1)^2 + F(n)^2
F(2n) = (2*F(n-1) + F(n)) * F(n)
Sie benötigen eine Bibliothek, mit der Sie mit großen Ganzzahlen arbeiten können. Ich benutze die BigInteger-Bibliothek von https://mattmccutchen.net/bigint/ .
Beginnen Sie mit einer Reihe von Fibonacci-Zahlen. Verwenden Sie Fibs [0] = 0, Fibs [1] = 1, Fibs [2] = 1, Fibs [3] = 2, Fibs [4] = 3 usw. In diesem Beispiel verwende ich ein Array der ersten 501 (0 zählen). Die ersten 500 Fibonacci-Zahlen ungleich Null finden Sie hier: http://home.hiwaay.net/~jalison/Fib500.html . Es erfordert ein wenig Bearbeitung, um es in das richtige Format zu bringen, aber das ist nicht zu schwierig.
Dann können Sie mit dieser Funktion (in C) eine beliebige Fibonacci-Zahl finden:
BigUnsigned GetFib(int numfib)
{
int n;
BigUnsigned x, y, fib;
if (numfib < 501) // Just get the Fibonacci number from the fibs array
{
fib=(stringToBigUnsigned(fibs[numfib]));
}
else if (numfib%2) // numfib is odd
{
n=(numfib+1)/2;
x=GetFib(n-1);
y=GetFib(n);
fib=((x*x)+(y*y));
}
else // numfib is even
{
n=numfib/2;
x=GetFib(n-1);
y=GetFib(n);
fib=(((big2*x)+y)*y);
}
return(fib);
}
Ich habe dies für die 25.000ste Fibonacci-Zahl und dergleichen getestet.
Hier ist meine rekursive Version, die log (n) mal rekursiv ist. Ich denke, dass es am einfachsten ist, in rekursiver Form zu lesen:
def my_fib(x):
if x < 2:
return x
else:
return my_fib_helper(x)[0]
def my_fib_helper(x):
if x == 1:
return (1, 0)
if x % 2 == 1:
(p,q) = my_fib_helper(x-1)
return (p+q,p)
else:
(p,q) = my_fib_helper(x/2)
return (p*p+2*p*q,p*p+q*q)
Es funktioniert , weil Sie berechnen kann fib(n),fib(n-1)
unter Verwendung , fib(n-1),fib(n-2)
wenn n ungerade ist , und wenn n gerade ist, können Sie berechnen , fib(n),fib(n-1)
verwenden fib(n/2),fib(n/2-1)
.
Der Basisfall und der ungerade Fall sind einfach. Um den geraden Fall abzuleiten, beginnen Sie mit a, b, c als aufeinanderfolgende Fibonacci-Werte (z. B. 8,5,3) und schreiben Sie sie in eine Matrix mit a = b + c. Beachten:
[1 1] * [a b] = [a+b a]
[1 0] [b c] [a b]
Daraus sehen wir, dass eine Matrix der ersten drei Fibonacci-Zahlen, mal eine Matrix aus drei aufeinanderfolgenden Fibonacci-Zahlen, gleich der nächsten ist. Also wissen wir das:
n
[1 1] = [fib(n+1) fib(n) ]
[1 0] [fib(n) fib(n-1)]
Damit:
2n 2
[1 1] = [fib(n+1) fib(n) ]
[1 0] [fib(n) fib(n-1)]
Die Vereinfachung der rechten Seite führt zum geraden Fall.
mit R.
l1 <- (1+sqrt(5))/2
l2 <- (1-sqrt(5))/2
P <- matrix(c(0,1,1,0),nrow=2) #permutation matrix
S <- matrix(c(l1,1,l2,1),nrow=2)
L <- matrix(c(l1,0,0,l2),nrow=2)
C <- c(-1/(l2-l1),1/(l2-l1))
k<-20 ; (S %*% L^k %*% C)[2]
[1] 6765
Die Festkomma-Arithmetik ist ungenau. Jasons C # -Code gibt eine falsche Antwort für n = 71 (308061521170130 anstelle von 308061521170129) und darüber hinaus.
Verwenden Sie für eine korrekte Antwort ein Computeralgebrasystem. Sympy ist eine solche Bibliothek für Python. Es gibt eine interaktive Konsole unter http://live.sympy.org/ . Kopieren Sie diese Funktion und fügen Sie sie ein
phi = (1 + sqrt(5)) / 2
def f(n):
return floor(phi**n / sqrt(5) + 1/2)
Dann berechnen
>>> f(10)
55
>>> f(71)
308061521170129
Vielleicht möchten Sie versuchen, zu inspizieren phi
.
Abgesehen von der Feinabstimmung durch mathematische Ansätze besteht eine der besten optimalen Lösungen (glaube ich) darin, ein Wörterbuch zu verwenden, um wiederholte Berechnungen zu vermeiden.
import time
_dict = {1:1, 2:1}
def F(n, _dict):
if n in _dict.keys():
return _dict[n]
else:
result = F(n-1, _dict) + F(n-2, _dict)
_dict.update({n:result})
return result
start = time.time()
for n in range(1,100000):
result = F(n, _dict)
finish = time.time()
print(str(finish - start))
Wir beginnen mit einem einfachen Wörterbuch (die ersten beiden Werte der Fibonacci-Sequenz) und fügen dem Wörterbuch ständig Fibonacci-Werte hinzu.
Die ersten 100000 Fibonacci-Werte (Intel Xeon CPU E5-2680 bei 2,70 GHz, 16 GB RAM, Windows 10-64-Bit-Betriebssystem) dauerten etwa 0,7 Sekunden.
Siehe hier den Algorithmus zum Teilen und Erobern
Der Link hat einen Pseudocode für die Matrixexponentiation, die in einigen anderen Antworten auf diese Frage erwähnt wurde.
Sie können die seltsame Quadratwurzelgleichung verwenden, um eine genaue Antwort zu erhalten. Der Grund ist, dass $ \ sqrt (5) $ am Ende herausfällt. Sie müssen nur die Koeffizienten mit Ihrem eigenen Multiplikationsformat verfolgen.
def rootiply(a1,b1,a2,b2,c):
''' multipy a1+b1*sqrt(c) and a2+b2*sqrt(c)... return a,b'''
return a1*a2 + b1*b2*c, a1*b2 + a2*b1
def rootipower(a,b,c,n):
''' raise a + b * sqrt(c) to the nth power... returns the new a,b and c of the result in the same format'''
ar,br = 1,0
while n != 0:
if n%2:
ar,br = rootiply(ar,br,a,b,c)
a,b = rootiply(a,b,a,b,c)
n /= 2
return ar,br
def fib(k):
''' the kth fibonacci number'''
a1,b1 = rootipower(1,1,5,k)
a2,b2 = rootipower(1,-1,5,k)
a = a1-a2
b = b1-b2
a,b = rootiply(0,1,a,b,5)
# b should be 0!
assert b == 0
return a/2**k/5
if __name__ == "__main__":
assert rootipower(1,2,3,3) == (37,30) # 1+2sqrt(3) **3 => 13 + 4sqrt(3) => 39 + 30sqrt(3)
assert fib(10)==55
Hier ist ein Einzeiler, der F (n) unter Verwendung von ganzen Zahlen der Größe O (n) in O (log n) -Arithmetikoperationen berechnet:
for i in range(1, 50):
print(i, pow(2<<i, i, (4<<2*i)-(2<<i)-1)//(2<<i))
Die Verwendung von ganzen Zahlen der Größe O (n) ist sinnvoll, da dies mit der Größe der Antwort vergleichbar ist.
Um dies zu verstehen, sei phi der goldene Schnitt (die größte Lösung für x ^ 2 = x + 1) und F (n) die n-te Fibonacci-Zahl, wobei F (0) = 0, F (1) = F. (2) = 1
Nun ist phi ^ n = F (n-1) + F (n) phi.
Beweis durch Induktion: phi ^ 1 = 0 + 1 * phi = F (0) + F (1) phi. Und wenn phi ^ n = F (n-1) + F (n) phi, dann ist phi ^ (n + 1) = F (n-1) phi + F (n) phi ^ 2 = F (n-1) phi + F (n) (phi + 1) = F (n) + (F (n) + F (n - 1)) phi = F (n) + F (n + 1) phi. Der einzige schwierige Schritt bei dieser Berechnung ist der, der phi ^ 2 durch (1 + phi) ersetzt, was folgt, weil phi der goldene Schnitt ist.
Auch Zahlen der Form (a + b * phi), wobei a, b ganze Zahlen sind, werden unter Multiplikation geschlossen.
Beweis: (p0 + p1 · phi) (q0 + q1 · phi) = p0q0 + (p0q1 + q1p0) phi + p1q1 · phi ^ 2 = p0q0 + (p0q1 + q1p0) phi + p1q1 * (phi + 1) = ( p0q0 + p1q1) + (p0q1 + q1p0 + p1q1) * phi.
Mit dieser Darstellung kann man Phi ^ n in O (log n) Integer-Operationen unter Verwendung von Exponentiation durch Quadrieren berechnen. Das Ergebnis ist F (n-1) + F (n) phi, woraus man die n-te Fibonacci-Zahl ablesen kann.
def mul(p, q):
return p[0]*q[0]+p[1]*q[1], p[0]*q[1]+p[1]*q[0]+p[1]*q[1]
def pow(p, n):
r=1,0
while n:
if n&1: r=mul(r, p)
p=mul(p, p)
n=n>>1
return r
for i in range(1, 50):
print(i, pow((0, 1), i)[1])
Beachten Sie, dass der Großteil dieses Codes eine Standardfunktion zur Potenzierung durch Quadrieren ist.
Um auf die Einzeiler , die diese Antwort beginnt, kann man feststellen , dass repräsentiert phi durch eine ausreichend große ganze Zahl X
, kann man durchführen (a+b*phi)(c+d*phi)
als Integer - Operation (a+bX)(c+dX) modulo (X^2-X-1)
. Dann pow
kann die Funktion durch die Standard-Python- pow
Funktion ersetzt werden (die bequemerweise ein drittes Argument enthält, z
das das Ergebnis modulo berechnet z
. Das X
gewählte ist 2<<i
.
Ich bin auf einige der Methoden zur Berechnung von Fibonacci mit effizienter Zeitkomplexität gestoßen.
Methode 1 - Dynamische Programmierung Nun ist hier die Unterstruktur allgemein bekannt, daher werde ich direkt zur Lösung springen -
static int fib(int n)
{
int f[] = new int[n+2]; // 1 extra to handle case, n = 0
int i;
f[0] = 0;
f[1] = 1;
for (i = 2; i <= n; i++)
{
f[i] = f[i-1] + f[i-2];
}
return f[n];
}
Eine platzoptimierte Version von oben kann wie folgt durchgeführt werden:
static int fib(int n)
{
int a = 0, b = 1, c;
if (n == 0)
return a;
for (int i = 2; i <= n; i++)
{
c = a + b;
a = b;
b = c;
}
return b;
}
Methode 2- (Verwenden der Potenz der Matrix {{1,1}, {1,0}})
Dies ist ein O (n), das auf der Tatsache beruht, dass, wenn wir die Matrix M = {{1,1}, {1,0}} n-mal mit sich selbst multiplizieren (mit anderen Worten die Leistung (M, n) berechnen), dann Wir erhalten die (n + 1) -te Fibonacci-Zahl als Element in Zeile und Spalte (0, 0) in der resultierenden Matrix. Diese Lösung hätte O (n) Zeit.
Die Matrixdarstellung gibt den folgenden geschlossenen Ausdruck für die Fibonacci-Zahlen: Fibonaccimatrix
static int fib(int n)
{
int F[][] = new int[][]{{1,1},{1,0}};
if (n == 0)
return 0;
power(F, n-1);
return F[0][0];
}
/*multiplies 2 matrices F and M of size 2*2, and
puts the multiplication result back to F[][] */
static void multiply(int F[][], int M[][])
{
int x = F[0][0]*M[0][0] + F[0][1]*M[1][0];
int y = F[0][0]*M[0][1] + F[0][1]*M[1][1];
int z = F[1][0]*M[0][0] + F[1][1]*M[1][0];
int w = F[1][0]*M[0][1] + F[1][1]*M[1][1];
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
/*function that calculates F[][] raise to the power n and puts the
result in F[][]*/
static void power(int F[][], int n)
{
int i;
int M[][] = new int[][]{{1,1},{1,0}};
// n - 1 times multiply the matrix to {{1,0},{0,1}}
for (i = 2; i <= n; i++)
multiply(F, M);
}
Dies kann optimiert werden, um in O (Logn) -Zeitkomplexität zu arbeiten. Wir können eine rekursive Multiplikation durchführen, um die Leistung (M, n) in der vorherigen Methode zu erhalten.
static int fib(int n)
{
int F[][] = new int[][]{{1,1},{1,0}};
if (n == 0)
return 0;
power(F, n-1);
return F[0][0];
}
static void multiply(int F[][], int M[][])
{
int x = F[0][0]*M[0][0] + F[0][1]*M[1][0];
int y = F[0][0]*M[0][1] + F[0][1]*M[1][1];
int z = F[1][0]*M[0][0] + F[1][1]*M[1][0];
int w = F[1][0]*M[0][1] + F[1][1]*M[1][1];
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
static void power(int F[][], int n)
{
if( n == 0 || n == 1)
return;
int M[][] = new int[][]{{1,1},{1,0}};
power(F, n/2);
multiply(F, F);
if (n%2 != 0)
multiply(F, M);
}
Methode 3 (O (log n) Zeit) Nachfolgend finden Sie eine weitere interessante Wiederholungsformel, mit der die n-te Fibonacci-Zahl in O (log n) Zeit ermittelt werden kann.
Wenn n gerade ist, dann ist k = n / 2: F (n) = [2 · F (k - 1) + F (k)] · F (k)
Wenn n ungerade ist, dann ist k = (n + 1) / 2 F (n) = F (k) * F (k) + F (k-1) * F (k-1) Wie funktioniert diese Formel? Die Formel kann aus der obigen Matrixgleichung abgeleitet werden. Fibonaccimatrix
Wenn wir die Determinante auf beiden Seiten nehmen, erhalten wir (-1) n = Fn + 1Fn-1 - Fn2. Da außerdem AnAm = An + m für jede quadratische Matrix A ist, können die folgenden Identitäten abgeleitet werden (sie werden aus zwei verschiedenen Koeffizienten von erhalten das Matrixprodukt)
FmFn + Fm-1Fn-1 = Fm + n-1
Indem Sie n = n + 1 setzen,
FmFn + 1 + Fm-1Fn = Fm + n
Setzen von m = n
F2n-1 = Fn2 + Fn-12
F2n = (Fn-1 + Fn + 1) Fn = (2Fn-1 + Fn) Fn (Quelle: Wiki)
Um die Formel zu beweisen, müssen wir einfach Folgendes tun: Wenn n gerade ist, können wir k = n / 2 setzen. Wenn n ungerade ist, können wir k = (n + 1) / 2 setzen
public static int fib(int n)
{
if (n == 0)
return 0;
if (n == 1 || n == 2)
return (f[n] = 1);
// If fib(n) is already computed
if (f[n] != 0)
return f[n];
int k = (n & 1) == 1? (n + 1) / 2
: n / 2;
// Applyting above formula [See value
// n&1 is 1 if n is odd, else 0.
f[n] = (n & 1) == 1? (fib(k) * fib(k) +
fib(k - 1) * fib(k - 1))
: (2 * fib(k - 1) + fib(k))
* fib(k);
return f[n];
}
Methode 4 - Verwenden einer Formel Bei dieser Methode implementieren wir direkt die Formel für den n-ten Term in der Fibonacci-Reihe. Zeit O (1) Raum O (1) Fn = {[(√5 + 1) / 2] ^ n} / √5
static int fib(int n) {
double phi = (1 + Math.sqrt(5)) / 2;
return (int) Math.round(Math.pow(phi, n)
/ Math.sqrt(5));
}
Referenz: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibFormula.html
Wir sollten zunächst beachten Sie, dass Fibonacci - Zahlen (F(n))
wachsen sehr schnell mit n
und kann nicht in dargestellt werden 64 Bits für n
größer als 93. So ein Programm für sie für eine solche Berechnung n
Bedarf zusätzliche Mechanismen zu verwenden , auf diesen großen Zahlen zu operieren. Wenn man nur die Anzahl der Operationen (mit großer Anzahl) berücksichtigt, erfordert der Algorithmus, um sie sequentiell zu berechnen, eine lineare Anzahl von Operationen.
Wir können von der folgenden Identität über Fibonacci-Zahlen profitieren:
F(2m) = 2*F(m)*F(m+1) − (F(m))^2
F(2m+1) = (F(m))^2 + (F(m+1))^2
(Ein Symbol wie A ^ 2 bezeichnet das Quadrat von A).
Also, wenn wir wissen , F(m)
und F(m+1)
können wir direkt berechnen F(2m)
und F(2m+1)
.
Betrachten Sie die binäre Darstellung von n
. Beachten Sie, dass x = 1
wir beginnend mit x = n
iterativ verdoppeln und möglicherweise 1 hinzufügen können x
. Dies kann durch Iterieren über die Bits von n
und Überprüfen, ob es 0 oder 1 ist, erfolgen.
Die Idee ist, dass wir F(x)
synchron bleiben können x
. In jeder solchen Iteration können wir, wenn wir verdoppeln x
und möglicherweise 1 addieren x
, auch den neuen Wert der F(x)
Verwendung des früheren Werts von F(x)
und F(x+1)
mit den obigen Gleichungen berechnen.
Da die Anzahl der Iterationen logarithmisch ist n
, sind auch die Gesamtoperationen (mit großer Anzahl) logarithmisch n
.
Weitere Einzelheiten finden Sie im Abschnitt "Verbesserter Algorithmus" dieses Artikels .