面试题9:递归和非递归

1.题目:编写函数,计算斐波拉契数列的第n项。定义如图


分析:

这是一个经典的问题,很多人都会用递归的方法去解决,但是实际的效果真的可以用吗,如果采用递归的方法,在求斐波拉契数列第n项的过程中,不仅会存在重复计算的项,而且而且函数调用自身也是有时间和空间消耗的,涉及到往栈中压入数据和弹出数据,这将消耗大量的时间。而采用循环计算的方法则不会存在这种问题,时间复杂度为O(n)。关于计算斐波拉契数列第n项还有一种方法就是用矩阵相乘的方法。


用数学归纳法很容易证明,这样可以将时间复杂度缩短至O(lgn).


源码:

/*递归和非递归的比较*/
#include<iostream>
#include <time.h>
#include <cassert>
using namespace std;

// ====================方法1:递归====================
long long Fibonacci_Solution1(unsigned int n)
{

	if (n <= 0)
		return 0;

	if (n == 1)
		return 1;

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

// ====================方法2:循环====================
long long Fibonacci_Solution2(unsigned n)
{
	int result[2] = { 0, 1 };
	if (n < 2)
		return result[n];

	long long  fibNMinusOne = 1;
	long long  fibNMinusTwo = 0;
	long long  fibN = 0;
	for (unsigned int i = 2; i <= n; ++i)//更新前两项的值
	{
		fibN = fibNMinusOne + fibNMinusTwo;

		fibNMinusTwo = fibNMinusOne;
		fibNMinusOne = fibN;
	}

	return fibN;
}
// ====================方法3:基于矩阵乘法====================
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;
};

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);
}

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)
	{
		matrix = MatrixPower((n - 1) / 2);
		matrix = MatrixMultiply(matrix, matrix);
		matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0));
	}

	return matrix;
}

long long Fibonacci_Solution3(unsigned int n)
{
	int result[2] = { 0, 1 };
	if (n < 2)
		return result[n];

	Matrix2By2 PowerNMinus2 = MatrixPower(n - 1);
	return PowerNMinus2.m_00;
}
int main()
{

	long long result;
	clock_t start, finish;
	double duration;
	start = clock();
	result = Fibonacci_Solution1(40);//递归方法计算
	finish = clock();
	duration = (double)(finish - start) / CLOCKS_PER_SEC;
	cout << "递归的结果是: "<<result<<"--"<<"递归耗时:" << duration << "秒" << endl;
	start = clock();
	result = Fibonacci_Solution2(40);//循环方法计算
	finish = clock();
	duration = (double)(finish - start) / CLOCKS_PER_SEC;
	cout << "循环的结果是: " << result << "--" << "循环耗时:" << duration << "秒" << endl;
	start = clock();
	result = Fibonacci_Solution3(40);//矩阵相乘的方法计算
	finish = clock();
	duration = (double)(finish - start) / CLOCKS_PER_SEC;
	cout << "矩阵乘法的结果是: " << result << "--" << "矩阵相乘耗时:" << duration << "秒" << endl;

	system("PAUSE");
	return 0;
}

结果:




相关的变形题目:

1.青蛙跳台阶的问题,青蛙一次可以跳上一级台阶,也可以跳两级台阶,问青蛙跳上n级的台阶的总共的跳法。

2.用2x1的小矩形覆盖更大的矩形的问题,n个2x1的小矩形覆盖一个2xn的大矩形的方法总数。

这些都是类似斐波拉契数列的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值