跳台阶问题|斐波那契递归的复杂度问题|整数划分问题

【问题】

台阶一共有N节,一次可以跳1节或者2节,问有多少次跳法?如果一次可以跳1节、2节或者3节呢?

【分析】

定义f(N)为第几节台阶时候的跳法,那么,
  1. N=1时,f(N)=1; 
  2. N=2时, f(N)=2;因为有每次跳一步和一次跳两步两种
  3. 当N>2时,如果第一次跳1阶,那么要跳到第N节有,需要将剩下的N-1节跳完,f(N-1);如果第一次跳2阶,那么需要将剩下的N-2节跳完,有f(N-2)种跳法,两种起始跳法互斥,所以由f(N)=f(N-1)+f(N-2)

【代码】

long long fibonacci_soluction(int N)
{

	if(N <=2)
		return N;
	else
		return fibonacci_soluction(N-1)+fibonacci_soluction(N-2);

}

同理,若是一次可以跳1阶、2阶或者3阶,那么
  1. f(N)=1 N=1
  2. f(N)=2 N=2
  3. f(N)=4 N=3
  4. f(N)=f(N-1)+f(N-2)+f(N-3) n>3
代码如下:
long long fibonacci_soluction2(int N)
{
	if(N == 1)
		return 1;
	if(N == 2)
		return 2;
	if(N == 3)
		return 4;
	else
		return fibonacci_soluction2(N-1)+fibonacci_soluction2(N-2)+fibonacci_soluction2(N-3);
}


【思考】菲波那切数列时间空间复杂度

转化成斐波那契数列递归求解,貌似是一个漂亮的解法,但是时间O(2^N)和空间复杂度O(N)不敢恭维,改用递推,时间复杂度为O(N),空间复杂度为O(1)
long long fibonacci_soluction_rec(int N)
{

	if(N <= 2)
		return N;
	long long a, b, c;
	a = 1, b = 2;
	int i;
	for (int i = 3; i <= N; i++)
	{
		c = a + b;
		a = b;
		b = c;
	}	
	return c;

}

但这是实现菲波那切数列最优的方法么?参考 http://www.gocalf.com/blog/calc-fibonacci.html
答案:矩阵法是最快的算法,具体推导见上面的链接用python实现的,用C++实现的http://zhedahht.blog.163.com/blog/static/25411174200722991933440/
最终的代码如下:
/*  f[n]       1*f[n-1] + 1* f[n-2]    1  1    f[N-1]   | 1  1 |^(N-1)    f[1]
-----  =   ---------------      =       *         =*
f[n-1]   1*f[n-1] + 0* f[n-1]   1  0  f[N-2]   | 1  0 |  f[0]
转变为求1  1 二维矩阵的N-1次幂的形式
1  0 
/  an/2*an/2                      n为偶数时
an=
\  a(n-1)/2*a(n-1)/2            n为奇数时
这样只需logN次就行了
*/
struct matrix_2by2
{
	matrix_2by2(long long a_00 = 0,	long long a_01 = 0,	long long a_10 = 0, long long a_11 = 0)
	:a00(a_00),a01(a_01),a10(a_10),a11(a_11)//为书写方便,给struct一个构造函数
	{

	}
	long long a00;
	long long a01;
	long long a10;
	long long a11;	
};
typedef struct matrix_2by2 matrix_2by2;
matrix_2by2 matrix_2by2_multiple(const matrix_2by2 A, const matrix_2by2 B)
{
	return matrix_2by2
	(
		A.a00*B.a00 + A.a01*B.a10,
		A.a00*B.a01 + A.a01*B.a11,
		A.a10*B.a00 + A.a11*B.a10,
		A.a10*B.a01 + A.a11*B.a11	
	);

}
matrix_2by2 matrix_pow(int N)
{
	assert(N > 0);
	matrix_2by2 matrix;
	if (N == 1)
	{
		return matrix_2by2(1, 1, 1, 0);
	}
	if (N % 2 == 0)
		matrix = matrix_2by2_multiple(matrix_pow(N/2), matrix_pow(N/2));

	if (N % 2 == 1)
	{
		matrix = matrix_2by2_multiple(matrix_pow((N-1)/2), matrix_pow((N-1)/2));
		matrix = matrix_2by2_multiple(matrix, matrix_2by2(1,1,1,0));
	}
	return matrix;
}

long long matrix_fabonacci(int N)
{
	if(N <=2)
		return N;
	matrix_2by2 res = matrix_pow(N);
	return res.a00;	
}

测试代码

#include <time.h>
#include <iostream>
using namespace std;
int main()
{
	
	time_t begin, end;
	begin = clock();
	fibonacci_soluction_rec(10000000);
	end = clock();
	cout<<"使用递推fibonacci(100)用时"<<end-begin<<endl;
	begin = clock();
	matrix_fabonacci(10000000);
	end = clock();
	cout<<"使用矩阵fibonacci(100)用时"<<end-begin<<endl;

}
不知为什么,我测试的矩阵方法竟然比递归的方法慢了50多倍!有时间在考虑下~~

【思考】当跳的步数不止三个呢,这就转化为整数规划的问题

long long equationCount(int n, int m)
{
	assert(m >0 && n>0);
	if (m==1 || n==1)
		return 1;
	if (n <= m)
		return 1+equationCount(n, n-1);
	if (n > m)
		return equationCount(n-m, m)+equationCount(n, m-1);

}

当然,对上述递归算法实际中需要进行优化。(完,断断续续写了三天=_=)

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值