oracle斐波那契数列累加,斐波拉契数列及其应用 (递归与循环)

相信大家一定不陌生斐波那契数列吧,今天小G就和大伙儿分享一下斐波拉契数列背后隐藏的递归和循环思想。

先简单描述一下,什么是斐波拉契数列呢?

斐波那契数列又称黄金分割数列。数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”。它指的是这样一个数列:0、1、1、2、3、5、8、13、21、……在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*),用文字来说,就是斐波那契数列列由 0 和 1 开始,之后的斐波那契数列系数就由之前的两数相加。特别指出:0不是第一项,而是第零项。现在我们想要编程实现这样一个数列,想想该怎么办?请你输出斐波那契数列的第n项(从0开始,第0项为0)。

这个问题可以说是迭代(Iteration)VS 递归(Recursion),f(n) = f(n-1) + f(n-2),第一眼看就是递归啊,简直完美的递归环境!!递归肯定很easy!!这样想着,小G兴奋的敲下了关键的两三行代码,如下:

class Solution:

def Fibonacci(self, n):

if(n<=1): return n;

else: return self.Fibonacci(n-1)+self.Fibonacci(n-2)

Hold on!Hold on!! Hold on!!!

哗哗地,小G的脑袋里突然响起了一个冰冷的声音:如果给你一个超大数值的n怎么办呢,比如说n=10000000000。小G看了一眼刚刚敲好的程序,陷入了沉思:原来自己的程序里存在着大量的重复计算呀,而且重复的情况还很严重!举个小点的例子,n=4,看看程序怎么跑的:

Fibonacci(4) = Fibonacci(3) + Fibonacci(2);

= Fibonacci(2) + Fibonacci(1) + Fibonacci(1) + Fibonacci(0);

= Fibonacci(1) + Fibonacci(0) + Fibonacci(1) + Fibonacci(1) + Fibonacci(0);

由于我们的代码并没有记录Fibonacci(1)和Fibonacci(0)的结果,对于程序来说它每次递归都是未知的,因此光是n=4时f(1)就重复计算了3次之多。那么如何求解呢,动态规划似乎不错,以一定的空间代价避免代价更大的重复计算的栈空间浪费,关于动态规划三个条件:最优子结构、无后效性、子问题重叠这些就不谈了,因为理(wo)论(ye)性(bu)太(tai)强(dong)了。

想到这里,小G如释重负,搓搓双手敲下了下面的代码:

class Solution:

def Fibonacci(self, n):

l = [0,1]

while len(l)<=n:

l.append(l[-1]+l[-2])

return l[n]

取一个超级大的n,看一下运行的时间和占用的内存 :

0b54daa668e11c9190360bda170b8f6e.png

嗯!效果还不错啊!!

其实斐波拉契数列这种想法有很多奇奇怪怪的变式花样,比如前一阵子小G看到一个关于跳台阶的问题。描述如下:

有一只可爱的小青蛙,闲着无聊想要锻炼身体,于是找了个废弃的郊外别墅练习“蛙跳”。由于体力有限,它一次只能跳上1级台阶,也可以发个力跳上2级。那么请你想一想,这只小青蛙跳上一个n级的台阶总共有多少种跳法呢?

我们可以把这个问题分解一下:

a. 如果两种跳法,1阶或者2阶,那么假定第一次跳的是一阶,那么剩下的是n-1个台阶,跳法是f(n-1);

b. 假定第一次跳的是2阶,那么剩下的是n-2个台阶,跳法是f(n-2)

c. 由a\b假设可以得出总跳法为: f(n) = f(n-1) + f(n-2)

d. 然后通过实际的情况可以得出:只有一阶的时候 f(1) = 1 ,只有两阶的时候可以有 f(2) = 2

e. 可以发现最终得出的是一个斐波那契数列!

注意:因为小青蛙每次都不能原地跳,所以初值记得调整一下哦。简单实现一下如下:

class Solution:

def jumpFloor(self, n):

l = [1,1]

while len(l)<=n:

l.append(l[-1]+l[-2])

return l[n]

看到小青蛙在这不停的蹦跶,一只路过的蛙界国家队运动员停下了脚步,对小青蛙说:“你这跳的也忒慢了吧。我可以一次性就跳上n级台阶,但我也可以每次偷个懒只跳1级台阶,或者跳上2级,3级,.....,n-1级等等。那么请你想一想,这个青蛙运动员跳上一个n级的台阶总共有多少种跳法呢?

来理一下思路吧。

因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级;

跳1级,剩下n-1级,则剩下跳法是f(n-1);

跳2级,剩下n-2级,则剩下跳法是f(n-2);

所以f(n)=f(n-1)+f(n-2)+...+f(1)

因为f(n-1)=f(n-2)+f(n-3)+...+f(1)

所以f(n)=2*f(n-1)

直接看图:

876e2e6010c2cd777927f00f9211273a.png

代码实现如下:

class Solution:

def jumpFloorII(self, n):

if n <=1: return n

else:

i, temp = 1, 1

while i < n:

l = 2*temp

temp = l

i += 1

return l

其实上面的解法有些繁琐了,小G是是一个追求简约的人。敲这么多行代码太折腾嘞。。。。

我们来换一个思路。

我们可以把每个台阶看作一块木板,让青蛙运动员跳上去,n个台阶就有n块木板,最后一块木板是青蛙到达的位子, 必须存在,其他 (n-1) 块木板可以任意选择是否存在,则每个木板有存在和不存在两种选择,(n-1) 块木板 就有 2^(n-1) 种跳法,可以直接得到结果。 2^(n-1)可以用位移操作进行,更快。

哈哈,这个想法是不是很清新脱俗呢?那么来实现一下吧。

class Solution:

def jumpFloorII(self, n):

return 1<

可能有些朋友还见过这样一类矩形覆盖问题。用2*1的小矩形横着或者竖着去覆盖更大的矩形,问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

其实这种问题说到底依旧是斐波那契数列,只是在初始值时不太一样。我们来分析一下:

b4bf017fa326379b94d3bb63085e30d3.png

代码实现一下吧:

class Solution:

def rectCover(self, n):

l =[0,1,2]

while len(l) <= n:

l.append(l[-1]+l[-2])

return l[n]

好了,今天的斐波拉契数列问题到此就要结束啦。最后来总结一下吧。

对待这类递归迭代问题,我们需要首先分析一下问题的初始情况。对于初始情况进行特殊分析,不怕麻烦的话,可以动手提笔写一写,总结一下是否存在着隐含的规律。递归问题说到底,就是把未来的解划归为以前解的组合。但是实现的话,如果只是简单机械的用递归来实现,必然会存在大量的重复计算,从而造成极大的运行时间开销。这时候最的方法就是采用迭代+循环。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值