Optimization of Fibonacci sequence generating algorithm

杀马特。学长 韩版系。学妹 提交于 2019-12-23 03:58:05

问题


As we all know, the simplest algorithm to generate Fibonacci sequence is as follows:

if(n<=0) return 0;
else if(n==1) return 1;
f(n) = f(n-1) + f(n-2);

But this algorithm has some repetitive calculation. For example, if you calculate f(5), it will calculate f(4) and f(3). When you calculate f(4), it will again calculate both f(3) and f(2). Could someone give me a more time-efficient recursive algorithm?


回答1:


One simple way is to calculate it iteratively instead of recursively. This will calculate F(n) in linear time.

def fib(n):
    a,b = 0,1
    for i in range(n):
        a,b = a+b,a
    return a



回答2:


Look here for implementation in Erlang which uses formula

. It shows nice linear resulting behavior because in O(M(n) log n) part M(n) is exponential for big numbers. It calculates fib of one million in 2s where result has 208988 digits. The trick is that you can compute exponentiation in O(log n) multiplications using (tail) recursive formula (tail means with O(1) space when used proper compiler or rewrite to cycle):
% compute X^N
power(X, N) when is_integer(N), N >= 0 ->
    power(N, X, 1).

power(0, _, Acc) ->
    Acc;
power(N, X, Acc) ->
    if N rem 2 =:= 1 ->
            power(N - 1,   X,     Acc * X);
        true ->
            power(N div 2, X * X, Acc)
    end.

where X and Acc you substitute with matrices. X will be initiated with

and Acc with identity I equals to

.


回答3:


Hint: One way you achieve faster results is by using Binet's formula:

Here is a way of doing it in Python:

from decimal import *

def fib(n):
    return int((Decimal(1.6180339)**Decimal(n)-Decimal(-0.6180339)**Decimal(n))/Decimal(2.236067977))



回答4:


you can save your results and use them :

public static long[] fibs;

public long fib(int n) {
    fibs = new long[n];
    return internalFib(n);
}
public long internalFib(int n) {
    if (n<=2) return 1;
    fibs[n-1] = fibs[n-1]==0 ? internalFib(n-1) : fibs[n-1];
    fibs[n-2] = fibs[n-2]==0 ? internalFib(n-2) : fibs[n-2];
    return fibs[n-1]+fibs[n-2];
}



回答5:


F(n) = (φ^n)/√5 and round to nearest integer, where φ is the golden ratio....

φ^n can be calculated in O(lg(n)) time hence F(n) can be calculated in O(lg(n)) time.




回答6:


// D Programming Language 

void vFibonacci ( const ulong X, const ulong Y, const int Limit ) {    
       // Equivalent : if ( Limit != 10 ). Former ( Limit ^ 0xA ) is More Efficient However.
       if ( Limit ^ 0xA ) {    
           write ( Y, " " ) ;
           vFibonacci ( Y, Y + X, Limit + 1 ) ;
       } ;
} ;

// Call As    
// By Default the Limit is 10 Numbers
vFibonacci ( 0, 1, 0 ) ;



回答7:


EDIT: I actually think Hynek Vychodil's answer is superior to mine, but I'm leaving this here just in case someone is looking for an alternate method.

I think the other methods are all valid, but not optimal. Using Binet's formula should give you the right answer in principle, but rounding to the closest integer will give some problems for large values of n. The other solutions will unnecessarily recalculate the values upto n every time you call the function, and so the function is not optimized for repeated calling.

In my opinion the best thing to do is to define a global array and then to add new values to the array IF needed. In Python:

import numpy

fibo=numpy.array([1,1])
last_index=fibo.size

def fib(n):
    global fibo,last_index
    if (n>0):
        if(n>last_index):
            for i in range(last_index+1,n+1):
                fibo=numpy.concatenate((fibo,numpy.array([fibo[i-2]+fibo[i-3]])))
            last_index=fibo.size
        return fibo[n-1]
    else:
        print "fib called for index less than 1"
        quit()

Naturally, if you need to call fib for n>80 (approximately) then you will need to implement arbitrary precision integers, which is easy to do in python.



来源:https://stackoverflow.com/questions/10924096/optimization-of-fibonacci-sequence-generating-algorithm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!