dawin

导航

斐波那契数列的时间复杂度详释与改进方法

二阶常系数线性差分方程

齐次差分方程

二阶常系数线性差分方程的一般形式为:
$y_n+ay_{n+1}+by_n=f(n), n=0, 1, 2,....(1-1)$
$其中a,b为已知常数,且b\not=0,f(n)为已知函数。$
$方程(1-1)的对应齐次方程为:$
$y_{n+2}+ay_{n+1}+by_n=0................................(1-2)$
$设y_n=\lambda^n为方程(1-2)的特解,其中\lambda为非零待定系数,代入方程后,有$
$\lambdan(\lambda2+a\lambda+b)=0$
$因\lambda\not=0,故函数y_n=\lambda^n是方程(1-2)的特解的充分必要条件是\lambda满足方程$
$\lambda^2+a\lambda+b=0............................................(1-3)$
方程(1-3)成为方程(1-1)或(1-2)的特征方程,特征方程的解称为特征根或特征值。
根据二次代数方程(1-3)解的三种情况,可以仿照二阶常系数齐次线性微分方程,分别给出方程(1-1)的通解。
1.1特征方程有两个相异实根
$即当判别式\Delta=a^2-4b>0时,方程(1-2)有两个相异实根$
$\lambda_1=\frac{1}{2}(-a-\sqrt\Delta),\lambda_2=\frac{1}{2}(-a+\sqrt\Delta)....(1-4)$
于是方程(1-2)有两个特解
$y_n{_1}=\lambda_1n,y_n{_2}=\lambda_2n$
$且由\frac{y_n{_1}}{y_n{_2}}=(\frac{\lambda_1}{\lambda_2})^n\not=常数,知y_n{_1}与y_n{_2}线性无关,从而得到方程(1-2)的通解$
$y_n=C_1\lambda_1n+C_2\lambda_2n,其中\lambda_1,
\lambda_2由式(1-4)给出,C_1,C_2为任意常数。$
1.2特征方程有二重根
$即当判别式\Delta=a2-4b=0时,方程(1-3)有二重根\lambda_1=\lambda_2=-\frac{1}{2}a,于是方程(1-2)有一个特解y_n{_1}=(-\frac{1}{2}a)n,可验证方程(1-2)有另一特解y_n{_2}=n(-\frac{1}{2}a)^n$
(注:系数n可参照二阶常系数线性齐次微分方程的通项证明求得)
$且由\frac{y_n{_1}}{y_n{_2}}=\frac{1}{n}\not=常数,知y_n{_1}与y_n{_2}线性无关,从而得到方程(10-2)的通解$
$y_n=(C_1+C_2n)(-\frac{1}{2}a)^n,其中C_1,C_2为任意常数。$
1.3特征方程有两个共轭复根
$即当判别式\Delta=a^2-4b<0时,方程(1-3)有两个共轭复根$
$\lambda_1=\frac{1}{2}(-a+i\sqrt{-\Delta}),\lambda_2=\frac{1}{2}(-a-i\sqrt{-\Delta})$
通过直接验证可知,方程(1-2)有两个特解
$y_n{_1}=r^ncos\beta n,y_n{_2}=r^nsin\beta n$
$其中r=\sqrt{(-\frac{a}{2})2+(\frac{\sqrt{-\Delta}}{2})2}=\sqrt{b}........(详见其他参考)$

斐波那契数列的递推式及通项公式

$递推式:
y_{n+2}=\begin {cases}
0, & n=0 \
1, & n=1........(1-5)\
y_{n+1}+y_n,& n>1
\end {cases}
$
$由式(1-2)可知,y_{n+2}-y_{n+1}-y_n=0............(1-6)$
其中a=-1,b=-1
$令y_n=\lambdan,式(1-6)化成\lambdan(\lambda^2-\lambda-1)=0,解得$
$y_n=C_1(\frac{1+\sqrt{5}}{2})n+C_2(\frac{1-\sqrt{5}}{2})n,由y_0=0,y_1=1可知$
$C_1=\frac{1}{\sqrt5},C_2=-\frac{1}{\sqrt5}$
$y_n=\frac{1}{\sqrt5}(\frac{1+\sqrt{5}}{2})n-\frac{1}{\sqrt5}(\frac{1-\sqrt{5}}{2})n即为通解$
可知,时间复杂度为指数形式。

改进方法:

1.时间复杂度为O(n)的方法:

    int Fibonacci(int n) {
        if (n<=0) {
            return 0;
        }
        if (n==1) {
            return 1;
        }
        int min=0;
        int max=1;
        int i=2;
        int result=0;
        while (i<=n) {
            result=min+max;
            min=max;
            max=result;
            ++i;
        }
        return result;
    

2.时间复杂度为O(logn)的方法:
根据式(1-5),可以化成矩阵的形式:
$
(\begin{matrix}y_{n+2}\y_{n+1}\end{matrix})=(\begin{matrix}1&1\1&0\end{matrix})
(\begin{matrix}y_{n+1}\y_{n}\end{matrix})=...=
(\begin{matrix}1&1\1&0\end{matrix})^{n+1}
(\begin{matrix}y_1\y_0\end{matrix})
$
$因而计算y_n就简化为计算矩阵的(n+1)次方,再对矩阵分解,计算矩阵(n-2)/2次方的平方,逐步分解,因而时间复杂度为O(logn)$

#include <iostream>
using namespace std;

class Matrix
{
public:
    int n;
    int **m;
    Matrix(int num)
    {
        m=new int*[num];
        for (int i=0; i<num; i++) {
            m[i]=new int[num];
        }
        n=num;
        clear();
    }
    void clear()
    {
        for (int i=0; i<n; ++i) {
            for (int j=0; j<n; ++j) {
                m[i][j]=0;
            }
        }
    }
    void unit()
    {
        clear();
        for (int i=0; i<n; ++i) {
            m[i][i]=1;
        }
    }
    Matrix operator=(const Matrix mtx)
    {
        Matrix(mtx.n);
        for (int i=0; i<mtx.n; ++i) {
            for (int j=0; j<mtx.n; ++j) {
                m[i][j]=mtx.m[i][j];
            }
        }
        return *this;
    }
    Matrix operator*(const Matrix &mtx)
    {
        Matrix result(mtx.n);
        result.clear();
        for (int i=0; i<mtx.n; ++i) {
            for (int j=0; j<mtx.n; ++j) {
                for (int k=0; k<mtx.n; ++k) {
                    result.m[i][j]+=m[i][k]*mtx.m[k][j];
                }   
            }
        }
        return result;
    }
};
int main(int argc, const char * argv[]) {
    unsigned int num=2;
    Matrix first(num);
    first.m[0][0]=1;
    first.m[0][1]=1;
    first.m[1][0]=1;
    first.m[1][1]=0;
    int t;
    cin>>t;
    Matrix result(num);
    result.unit();
    int n=t-2;
    while (n) {
        if (n%2) {
            result=result*first;
            }
        first=first*first;
        n=n/2;
    }
    cout<<(result.m[0][0]+result.m[0][1])<<endl;
    return 0;
}

posted on 2016-07-28 19:20  dawin  阅读(561)  评论(0编辑  收藏  举报