`
jishublog
  • 浏览: 869996 次
文章分类
社区版块
存档分类
最新评论

fibonacci数列

 
阅读更多

原文链接

解决了我一直没能理解的矩阵求fibonacci的困惑,原文链接:http://hawstein.com/posts/8.1.html

题目

写一个函数来产生第n个fibonacci数

解答

fibonacci数列的定义如下:

f(1) = f(2) = 1;
f(n) = f(n - 1) + f(n - 2);

根据递推公式,我们很容易写出递归和非递归代码

递归:

/**
 * 递归实现fibonacci数列
 */
long long int recursionFib(long long int n)
{
	if (n < 1)
		return -1;
	if (n == 1)
		return 1;
	if (n == 2)
		return 1;

	return recursionFib(n - 1) + recursionFib(n - 2);
}

非递归:

/**
 * 非递归实现fibonacci数列
 *
 * T = O(n)
 *
 */
long long int nonrecursionFib(int n)
{
	if (n < -1)
		return -1;
	if (n == 1)
		return 1;
	if (n == 2)
		return 1;

	long long int i, a, b, c;

	for (a = b = 1, i = 3; i <= n; i ++) {
		c = a + b;
		a = b;
		b = c;
	}

	return c;
}

非递归的时间复杂度已经是O(n),看起来简单快速,可是,我们还有更快的解决方法。根据上面的递推公式,我们可以得到它的矩阵版本:



继续化简得:



从上图可以看出,写成矩阵递推形式,可以让我们一推到底。最后的f(1) = f(2) = 1,因此,这个问题就转换成了,如何求矩阵的幂。要快速,不然就没什么意义了。我们先把问题退化一下,先不考虑矩阵的幂,如何求一个整数的幂。

/**
 * 求data的n次幂
 */
void numpow(long long int data, int n)
{
	long long int i, rs;

	for (i = 1, rs = 1; i <= n; i ++) {
		rs *= data;
	}

	printf("%lld\n", rs);
}

时间复杂度为O(n).现在让我们来考虑一种更快速的方法,假设我们要求m^13,然后我们把13写成二进制形式13 = 1101,一开始结果res = 1,我们要计算的幂可以写成:

m^13 = m^1 * m^4 * m^8

我们可以很直观的得出,如果指数13的二进制形式1101中某一位是1,那么,res就去乘以那一位对应的一个数

/**
 * 快速求data的n次幂
 *
 * T = O(logn)
 *
 */
void quickPow(long long int data, int n)
{
	long long int res;

	res = 1;

	while (n) {
		if (n & 1)	res *= data;

		data *= data;

		n >>= 1;
	}

	printf("%lld\n", res);
}

时间复杂度为O(logn),正是我们想要的快速版本。OK,这时候如果让你快速求矩阵的幂,是不是很简单了?只需要将实数乘法改成矩阵乘法即可

long long int s[2][2] = {{1, 0}, {0, 1}};
long long int f[2][2] = {{1, 1}, {1, 0}};


/**
 * 矩阵乘法
 */
void multiMatrix(long long int c[2][2], long long int a[2][2], long long int b[2][2])
{
	long long int i, j, k, t[2][2];
	
	memset(t, 0, sizeof(t));


	for (i = 0; i < 2; i ++) {
		for (j = 0; j < 2; j ++) {
			t[i][j] = 0;
			for (k = 0; k < 2; k ++) {
				t[i][j] += a[i][k] * b[k][j];
			}
		}
	}
	
	for (i = 0; i < 2; i ++) {
		for (j = 0; j < 2; j ++)
			c[i][j] = t[i][j];
	}
}

/**
 * 快速求fibonacci数列
 *
 * T = O(logn)
 *
 */
long long int quickFib(int n, long long int s[2][2], long long int f[2][2])
{
	if (n < 1)	return -1;
	if (n == 1 || n == 2)	return 1;

	n = n - 2;
	while (n) {
		if (n & 1)	multiMatrix(s, f, s);

		multiMatrix(f, f, f);

		n >>= 1;
	}

	return s[0][0] + s[0][1];
}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics