斐波那契数列及其对数时间算法

斐波那契数列及其对数时间算法

前些天做IEEE校内算法赛的时候,遇到了一道关于斐波那契数列的题,要求是对数时间;今天在牛课网上刷leetcode,看到爬楼梯问题,于是在网上搜索了一下,自己参考并总结了下斐波那契数列及其算法。主要参考了知乎这个问题下的回答最高赞回答
斐波那契数列大家应该都很熟悉:0 1 1 2 3 5 8… ,递推公式如下:
f ( n ) = { f ( n 1 ) + f ( n 2 ) i f 2 n ; f ( 0 ) = 0 , f ( 1 ) = 1 e l s e .

斐波那契数列的同向可以使用特征根法或者矩阵的乘积来解决:
f ( n ) = 1 5 ( ( 1 + 5 2 ) n ( 1 5 2 ) n ) .
下面介绍利用矩阵快速幂的对数时间的斐波那契数列算法:
首先从递推公式我们很容易得到:
[ f ( n + 1 ) f ( n ) ] = [ 1 1 1 0 ] [ f ( n ) f ( n 1 ) ] = [ 1 1 1 0 ] n [ f ( 1 ) f ( 0 ) ] .
不妨设 A = [ 1 1 1 0 ] ,那么我们的目标就是求矩阵A的n次幂
在介绍矩阵的快速幂算法之前,我们先介绍一下数的快速幂算法,数的快速幂算法一般有递归和位运算两种:

//递归版本
int my_power(int x, int n) {
    //n >= 0
    if(n == 0) return 1;
    return n % 2 ? x * my_power(x, n / 2) : my_power(x, n / 2);
}
//位运算版本
int my_power(int x, int n) {
    //n >= 0
    int result = 1;
    while(n) {
        if(n & 1) result *= x;
        x *= x;
        n >>= 1;
    }
    return result;
}

例如求 2 10 , 10 = ( 1010 ) ( 2 ) ,分二进制位上为1和为0两种情况讨论。
所以可以用同样的方法求矩阵的幂,我们声明了一个二阶矩阵类,只给了矩阵的四个元素、默认构造函数和重载operator*:

//Definition for 2-dimension matrix
struct Matrix {
    /*[m00, m01]
      [m10, m11]*/
    int m00, m01, m10, m11;
    Matrix(int a = 0, int b = 0, int c = 0, int d = 0) :
        m00(a), m01(b), m10(c), m11(d) { }
    Matrix& operator*(const Matrix& rhs) {
        //若要对大数取余,可以对下面的a,b,c,d取余运算。
        int a = this->m00 * rhs.m00 + this->m01 * rhs.m10; //% mod
        int b = this->m00 * rhs.m01 + this->m01 * rhs.m11; //% mod
        int c = this->m10 * rhs.m00 + this->m11 * rhs.m10; //% mod
        int d = this->m10 * rhs.m01 + this->m11 * rhs.m11; //% mod
        this->m00 = a; this->m01 = b;
        this->m10 = c; this->m11 = d;
        return *this;
    }
};
/*对数算法,利用矩阵的快速幂*/
Matrix fast_multi(int n) {
    Matrix m(1, 1, 1, 0), result(1, 0, 0, 1);
    while(n) {
        if(n & 1) result = result * m;
         m = m * m;
         n >>= 1;
    }
    return result;
}

因此斐波那契数列的第n项的算法为:

//这里没有考虑int溢出
int Fibonacci(int n) {
    Matrix m = fast_multi(n);
    return m.m10;
}

若斐波那契数列的初值为f0和f1:

//这里没有考虑int溢出
int Fibonacci(int n, int f0, int f1) {
    Matrix m = fast_multi(n);
    return (m.m10 * f1 + m.m11 * f0);
}

最开始说到IEEE校内算法赛的那道题是要求斐波那契数列的前n项和
S n = f ( n + 2 ) f ( 1 )
这个结论用数学归纳法是非常容易证明的。

总结:斐波那契数列在数学中非常重要,它的很多性质我也不懂,只是遇到问题就查资料解决,比如这个对数时间的斐波那契第n项的算法,以后如果遇到其他问题再来补吧!

猜你喜欢

转载自blog.csdn.net/qq_25467397/article/details/80407086
今日推荐