相信大家都对斐波那契数列已经相当的熟悉了,最多两分钟就可以写出来以下时间复杂度为O(N)的代码:

//递归实现
long long fib(int n)
{
	if (n =1 || n== 2)
	{
		return 1;
	}
	return (fib(n - 2) + fib(n - 1));
}

或者是这样的时间复杂度为O(N),空间复杂度为O(1):

//优化一:时间复杂度为O(N)
long long fib(int n)
{
	long long* fibarry = new long long[n + 1];
	fibarry[0] = 0;
	fibarry[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		fibarry[i] = fibarry[i - 1] + fibarry[i - 2];
	}
	long long ret = fibarry[n];
	delete fibarry;
	return ret;
}
//优化二:时间复杂度O(N)  空间复杂度O(1)
long long fib(int n)
{
	long long fibarry[3] = { 0, 1, 0 };
	for (int i = 2; i <= n; i++)
	{
		fibarry[2] = fibarry[0] + fibarry[1];
		fibarry[0] = fibarry[1];
		fibarry[1] = fibarry[2];
	}
	return fibarry[2];

}

 等等这些都是不错算法,都可以实现斐波那契数列的求解,但是今天我们讨论的是斐波那契数列的最优算法(当然博主水平就这样,各位亲有什么更加优的算法可以和博主分享)。这个算法的时间复杂度是O(logN)

 斐波那契数列的递推公式是:f(n)=f(n-1)+f(n-2);

  •  在线性代数中,类似于斐波那契数列这种递推式称为二阶递推式。我们可以用f(n)=af(n-1)+bf(n-2)将二阶递推式一般化。只要符合这种二阶递推式的算法,都可以将算法的时间复杂度降为O(logN)。当然,三阶,四阶....都可以,只要得到递推公式的n阶矩阵即可。如下:

     f(n)=af(n-1)+bf(n-2)+......

     (f(n),f(n-1))=(f(n-1),f(n-2))*matrix;(matrix是一个矩阵,几阶递推式就是几阶的矩阵,在这里是二阶的矩阵,斐波那契数列属于二阶)

  •   或许这样看起来还不够直观,我们带入一个例子看一下:

    f(3)=f(2)+f(1)->(f(3),f(2))=(f(2),f(1))*(matrix)^1;

    f(4)=f(3)+f(2)->(f(4),f(3))=(f(3),f(2))*(matrix)^1=(f(2),f(1))*(matrix)^2;

    .....

    f(n)=(f(2),f(1))*(matrix)^n-2;

    根据这些公式可以算出二阶的matrix={{1,1},{1,0}};

  •  算出了matrix后只差怎样算出matrix^n-2这个难题了。时间复杂度的降低,在于降低求矩阵的n次方的时间复杂度。其实这个问题也不难,我们先来看一个数怎样能快速算出num^n,

   例:10^68,我们通常是10*10乘上68次,这样时间效率为O(N),我们要用O(logN)方法算:

     68的二进制序列为:1000100

     10^68=10^64*10^4,也就是取出68二进制序列为1的位,其他忽略。这样我们只算了7次(二进制序列的长度)就可以算出10^68,效率就达到了O(logN)。(最优化算法的关键所在)

    现在大家知道了算num^n的优化算法,matrix^n也是一样的道理。不懂的可以去查阅一下线性代数的矩阵乘法。

  • 有了上面的基础,我们不难写出以下的代码:

  • //优化三   时间复杂度为O(logN)
    static const long long int Mod = 1000000007;//防止结果溢出
    static const int row = 2;
    static const int col = 2;
    struct DoubleArry//用来聚合二维数组
    {
    	long _arry[row][col];
    	DoubleArry()
    	{
    		for (int i = 0; i < row; ++i)
    			for (int j = 0; j < col; ++j)
    				_arry[i][j] = 0;
    	}
    	DoubleArry(long matrix[][col])
    	{
    		for (int i = 0; i < row; ++i)
    			for (int j = 0; j < col; ++j)
    				_arry[i][j] = matrix[i][j];
    	}
    	DoubleArry(const DoubleArry& d)
    	{
    		for (int i = 0; i < row; ++i)
    			for (int j = 0; j < col; ++j)
    				_arry[i][j] = d._arry[i][j];
    	}
    	DoubleArry& operator=(DoubleArry d)
    	{
    		swap(d._arry, _arry);
    		return *this;
    	}
    };
  • //两个矩阵相乘
    DoubleArry matrixMul(DoubleArry l, DoubleArry r)
    {
    	DoubleArry ret;
    	for (int i = 0; i<row; ++i)
    		for (int j = 0; j<col; ++j)
    		{
    			for (int k = 0; k<row; ++k)
    			{
    				ret._arry[i][j] += ((l._arry[i][k] %= Mod)*(r._arry[k][j] %= Mod)) %