From: http://blog.csdn.net/jcwkyl/article/details/3677747
以前只知道使用遞歸或遞推的方法,最近在CSDN論壇上學到一種新的解法,在自己所知的幾個算法裏,它具有最好的運行效率。這種方法使用下面這個關於Fibonacci數的矩陣恆等式:
這個算法就是根據這個恆等式,通過計算等式右邊的那個矩陣的n次方來計算第n個Fibonacci數。n次方的計算使用快速模冪算法,這樣計算n次方只用做log(n)次2*2矩陣的乘法,而每次乘法的計算時間是常量。所以,上述方法計算第n個Fibonacci數的時間複雜度是O(log(n))。相比之下,用遞歸來計算第n個Fibonacci的時間複雜度是O(Fn),是指數時間複雜度的。用遞推來計算,是O(n),然而當n很大時,n之於log(n),等於無窮大之於無窮小。
順便把關於Fibonacci的常用等式再總結一下:
From: http://tieba.baidu.com/p/1890441099
Fibonacci數是組合數學中非常重要的一個數列,它的遞推公式是:
F(1)=F(2)=1
F(n)=F(n-1)+F(n-2)
當然,用這個公式來計算F(n)是非常慢的,當計算F(n)時需要從F(1)一直計算到F(n)。Fibonacci數列還滿足一些其他的公式,如:
F(a+b+1)=F(a+1)*F(b+1)+F(a)*F(b)
利用這個公式,可以加速Fibonacci數的計算。我們考慮同時計算F(2n+1)和F(2n),則按照上面的公式:
F(2n+1)=F(n+1)*F(n+1)+F(n)*F(n)
F(2n)=F(n+1)*F(n)+F(n)*F(n-1)=F(n+1)*F(n)+F(n)*(F(n+1)-F(n))
這樣,F(2n+1)和F(2n)的計算變爲了F(n+1)和F(n)的計算,即下標變爲了原來的一半。重複利用這種方法,可以每次讓下標變爲原來的一半,總共需要大約log n次計算(以2爲底)。
當n較大時,後面的方法就比直接的遞推要快得多,比如當n=1000000時,後面的方法大概需要20次計算,而直接遞推的方法大概需要1000000次計算
From: http://blog.sina.com.cn/s/blog_993d2542010143qw.html
現在的問題轉換爲求矩陣{1, 1, 1, 0}的乘方。如果簡單第從0開始循環,n次方將需要n次運算,並不比前面的方法要快。但我們可以考慮乘方的如下性質:
/ an/2*an/2 n爲偶數時
an=
/ a(n-1)/2*a(n-1)/2 n爲奇數時
要求得n次方,我們先求得n/2次方,再把n/2的結果平方一下。如果把求n次方的問題看成一個大問題,把求n/2看成一個較小的問題。這種把大問題分解成一個或多個小問題的思路我們稱之爲分治法。這樣求n次方就只需要logn次運算了。
實現這種方式時,首先需要定義一個2×2的矩陣,並且定義好矩陣的乘法以及乘方運算。當這些運算定義好了之後,剩下的事情就變得非常簡單。完整的實現代碼如下所示。
#include <cassert>
///////////////////////////////////////////////////////////////////////
// A 2 by 2 matrix
///////////////////////////////////////////////////////////////////////
struct Matrix2By2
{
Matrix2By2
(
long long m00 = 0,
long long m01 = 0,
long long m10 = 0,
long long m11 = 0
)
:m_00(m00), m_01(m01), m_10(m10), m_11(m11)
{
}
long long m_00;
long long m_01;
long long m_10;
long long m_11;
};
///////////////////////////////////////////////////////////////////////
// Multiply two matrices
// Input: matrix1 - the first matrix
// matrix2 - the second matrix
//Output: the production of two matrices
///////////////////////////////////////////////////////////////////////
Matrix2By2 MatrixMultiply
(
const Matrix2By2& matrix1,
const Matrix2By2& matrix2
)
{
return Matrix2By2(
matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10,
matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11,
matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10,
matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11);
}
///////////////////////////////////////////////////////////////////////
// The nth power of matrix
// 1 1
// 1 0
///////////////////////////////////////////////////////////////////////
Matrix2By2 MatrixPower(unsigned int n)
{
assert(n > 0);
Matrix2By2 matrix;
if(n == 1)
{
matrix = Matrix2By2(1, 1, 1, 0);
}
else if(n % 2 == 0)
{
matrix = MatrixPower(n / 2);
matrix = MatrixMultiply(matrix, matrix);
}
else if(n % 2 == 1)
{