对数效率求斐波那契数

优化斐波那契数列计算:指数级到线性时间复杂度
博客探讨了斐波那契数列的指数级效率递归算法及其性能问题,并提出了一种基于矩阵乘方的线性时间复杂度解决方案。通过将指数转化为二进制并进行迭代,实现了效率的显著提升,但64位整数溢出问题需要使用大整数类来解决。

讨论一个著名的数列——斐波那契数列(Fibonacci sequence),其第0项为0,第1项为1,从其第2项开始,每一项都为前面两项的和,即:

F(n)=F(n-1)+F(n-2),n>1

F(0)=0,F(1)=1

C语言中,我们很自然能够得出如下的递归代码:

#define var __int64
var Fibonacci2(int n) {
	if (n <=1) {
		return n;
	}
	return Fibonacci2(n - 1) + Fibonacci2(n - 2);
}

其中var是由宏定义的,如果为int(4字节)类型,将在第47个数溢出,在其他语言中可能不需要考虑这个问题,这不是我们讨论的重点。该算法效率是指数级的,代码简短带来的问题可能就是性能的低下。读者可以尝试用循环和常数辅助空间实现\Theta (n)的算法。下面实现一种\Theta (\log n)的算法,基于等式:

\begin{bmatrix} F(n-1) &F(n) \\ F(n) & F(n+1) \end{bmatrix}=\begin{bmatrix} 0 &1 \\ 1 & 1 \end{bmatrix}^{n},n\geq 1

读者若感兴趣,可以用数学归纳法证明。

右式是一个2阶方阵,如果用普通矩阵乘法计算,效率类型也是8n\in \Theta (n),还需讨论如何更高效实现矩阵乘方。

对于指数为非负整数的乘方运算,我们可以将指数视为二进制,例如:

5^{20}=5^{(10100)b}=5^{(10000)b}\cdot 5^{(100)b}

可以通过迭代的方式得到权值,即:

a^{(n)b}=a^{(n>>1)b}\cdot a^{(n>>1)b}

具体实现为:

var pow(int a, int n){
	int sum = 1;
	int temp = a;
	while (n) {
		if (n % 2) {
			sum *= temp;
		}
		temp = temp * temp;
		n /= 2;
	}
	return sum;
}

将sum和temp的类型视为二维数组,初始的1就改为单位矩阵,以上的思想可以推广到矩阵乘方。

同时,由于sum和temp是对称阵,可以压缩为一维数组。

同样,矩阵乘法不是我们讨论的重点,以下为具体实现:

#include<stdio.h>
#define var __int64

var Fibonacci(int n) {
	var sum[] = { 1, 0, 1 };//a11,a12(a21),a22
	var temp[] = { 0, 1, 1 };//b11,b12(b21),b22
	var k;//辅助空间
	while (n) {
		if (n % 2) {
			k = sum[0] * temp[0] + sum[1] * temp[1];
			sum[1] = sum[0] * temp[1] + sum[1] * temp[2];
			sum[0] = k;
			sum[2] = k + sum[1];
		}
		k = temp[0] * temp[0] + temp[1] * temp[1];
		temp[1] = temp[0] * temp[1] + temp[1] * temp[2];
		temp[0] = k;
		temp[2] = k + temp[1];
		n /= 2;
	}
	return sum[1];
}

int main() {
	for (int i = 0; i < 100; i++) {
		printf("%d:%lld ", i, Fibonacci(i));
	}
}

 很明显,循环内部的基本操作是常数时间,该算法效率优化到了c\cdot \log_{2}n\in \Theta (\log n)

但第93个数已经溢出64位整数所能表示的范围,解决这个问题需要实现大整数类。

读者可用time.h库对多种算法单独进行测试,此算法优化幅度是非常大的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值