递归和循环---求斐波拉契数列的第N项


如果需要重复的多次计算相同的问题,通常会选择递归和循环两种方法。 递归是在函数内部调用该函数本身, 循环则是设置计算的初始值和终止条件,在一个范围内重复计算,如计算连续N个数之和。

递归

int add(int n){
	return n<=0?0:n+add(n-1)
}

循环

int add(int n){
	int result = 0;
	for(int i=1;i<=n;i++){
		result +=i;
	}
	return result;
}

从代码上可以看出递归相较于循环,代码更加的简介,更容易实现,但其缺点显著。由于递归是函数调用自身,而函数调用是有时间和空间的消耗的,每一次调用都需要在内存栈中分配空间已保存参数、返回地址及临时变量,且往栈里面压入数据和弹出数据都需要时间,这就不难理解递归的效率不如循环。
此外,递归中有可能很多计算都是重复计算,递归的本质是将一个问题分解成多个问题,如果多个问题存在相互重叠的部分,就会存在重复计算,接着以经典问题–斐波拉契数列 来往下进行。

问题:求斐波拉契数列的第N项。

写一个函数,输入N,求斐波那契数列的第N项。斐波拉契数列定义如下:
当N=0时,F(N) = 0
当N=1时,F(N) = 1
当N>1时,F(N) = F(N-1) + F(N-2)
递归解法:

long long Fibonacci(int n){
	if(n<=0)
		return 0;
	if(n == 1)
		return 1;
	return Fibonacci(n-1) + Fibonacci(n-2)
}

过程分析:
当N=10时,若要求得F(10),需先求得F(9) 和 F(8)。同样,要求得F(9),则需先求F(8)和F(7),以此类推。为了清晰直观,以树来描述,基于递归求斐波拉契数列的第10项的调用过程如下:
基于递归求斐波拉契数列的第10项的调用过程
从图中不难发现,这个树中的很多节点都是重复的,且重复的节点会随着N的增大而急剧增加。
优化思路-循环,从下往上计算,先根据F(0)和F(1)计算出F(2),再根据F(1)和F(2) 计算出F(3),以此类推就可以计算出F(N),时间复炸度为O(n)。

long long Fibonacci(int n){
	int result[2] = {0,1};
	if(n<2)
		return result[n];
	long long fibOne = 1; //N的前一项
	long long fibTwo = 0; //N的前二项
	long long fibN = 0;
	for(int i=2;i<n;i++){
	 	fibN = fibOne + fibTwo;
	 	fibTwo = fibOne;
	 	fibOne = fibN;
	}
	return fibN;
}
扩展1:青蛙跳台阶问题

一只🐸一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级台阶总共有多少种跳法。
分析: 假设只有一级台阶,那么,🐸只有一种跳法,若是两级台阶,那就有两种跳法,N级台阶呢,N级考虑两种情况:
一是第一次只跳一级,此时跳法数目等于剩下的n-1阶台阶的跳法数目;
二是第一次跳两级,此时跳法数目等于剩下的n-2阶台阶的跳法数目;

将其抽象为数学模型即为:
当N=1时,F(N) = 1
当N=2时,F(N) = 2
当N>2时,F(N) = F(N-1) + F(N-2)

可以看出,这就是一个斐波拉契数列问题。

扩展2:用2 × 1的小矩形覆盖一个2 × N的大矩形,总共有多少种方法。

此题也是斐波拉契数列的一种演变。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南疆晚歌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值