对数时间计算斐波那契数列的方法

本题目来源为SICP 习题1.19
先来看常规的斐波那契计算方法

int fib(int n)
{
    return n<2 ? n:fib(n-1)+fib(n-2);
}

不难发现,这种计算方法做了太多的冗余计算,实际上这一过程的增长相对于n是指数的,我们可以通过建立备忘录的方式来将算法复杂度减成线性的

#include 
using namespace std;
vector <int> opt; //opt在main函数中初始化大小为n
int fib(int n)
{
    if( n!=0 && opt[n]==0)
        opt[n]=fib(n-1)+fib(n-2);
    return opt[n];
}

另一种方法,利用迭代,减少函数调用:

#include 
#include 
using namespace std;
vector<int> opt;

int main(void)
{
    int i,n;
    cin>>n
    opt = vector<int>(n);
    opt[1]=1;
    for(i = 2;i <= n;i++)
        opt[i] = opt[i-1] + opt[i-2];
    cout<return 0;
}

存在着一种以对数步数求出斐波那契树的巧妙算法,我们先来看下面这种算法:

int fib(int n)
{
    return fib_iter(1,0,n);
}
int fib_iter(a,b,count)
{
    if(count == 0)
        return b;
    return fib_iter(a+b,a,count-1);
}

在这种算法中,我们每次递归都将a+b的值赋给a,把a的值赋给b,通过观察可以发现,从1和0开始将规则反复应用n次,将产生一对数fib(n)和fib(n+1),现在将这种规则看成
a = b*q + a*q + a*p
b = b*p + a*q
其中p=0,q=1
把这种变换称为T变换,那么对于T的平方来说,有:
a = (bp+aq)p+(bq+aq+ap)*q+(bq+aq+ap)*p = b(2pq+q^2)+a(p^2+2pq+3q^2)
b = (bp+aq)p+(bq+aq+ap)q = b(p^2+q^2)+a(q^2+2pq)

int fib(int n)
{
    return fib_iter(1,0,0,1,n);
}
int fib_iter(int a,int b,int p,int q,int count)
{
    if (count == 0)
        return b;
    else
        if (count%2)
            return fib_iter(b*p+a*q+a*p,b*p+a*q,p,q,count-1);
        else
            return fib_iter(a,b,p*p+q*q,q*q+2*p*q,count/2);
}

你可能感兴趣的:(C++)