【剑指Offer】第9题-斐波那契数列-Python
解法一 递归
通常用递归的解法会比较简洁,但也有显著的缺点。递归由于是函数自己调用自己,而函数调用是有时间和空间的消耗的。每一次函数调用,都需要在内存栈中分配空间以保存参数、返回地址及临时变量。而且往栈里压入数据和弹出数据也需要时间。
另外,递归中有可能很多计算都是重复的,从而对性能造成很大影响。递归的本质是把一个问题分割成多个小问题,如果多个小问题存在相互重叠的部分,那么就存在重复的计算。
递归还有可能引起更重要的问题,调用栈溢出。每一次函数调用在内存栈中分配空间,而每个进程的栈的容量是有限的,当递归调用的层级太多,就会超出栈的容量,从而导致栈溢出。
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n<3:
return n
return self.climbStairs(n-1)+self.climbStairs(n-2)
这里的递归解法存在严重的效率问题,会重复的计算很多项。而重复计算的节点个数随着n的增加急速增大
解法二 保存数列中间项
上面递归的缺点在于计算了很多重复项。可以通过保存数列中间项的方法来减少重复计算。下次需要计算的时候先查找是否计算过,如果计算过直接调用即可。
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n<3:
return n
temp = {}
if n in temp:
return temp[n]
else:
value = self.climbStairs(n-1)+self.climbStairs(n-2)
temp[n]=value
return value
解法三 逆向计算
更简单的方法是从下往上计算。首先根据f(0)和f(1)计算出f(2)。再根据f(1)和f(2)计算出f(3)。并且不保存计算中间结果。这种思路的时间复杂度是O(n)
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n<3:
return n
temp = 0
a = 1
b = 2
for i in range(3,n+1):
temp = a + b # 计算新值
a = b # 更新a b
b = temp
return temp
相似题目 爬楼梯
70. 爬楼梯
这个题目可以看做是斐波那契数列的应用。
首先考虑最简单的情况,如果只有1级台阶,显然只有一种跳法。如果有2级台阶,那就有两种跳的方法:一种是分两次跳,每次跳一级。一种是一次就跳两级。
接下来讨论一般的情况。 当n>2时,第一次跳的时候就有两种不同的选择。一是第一次只跳一级,此时数目为后面n-1阶跳法数目f(n-1).另一种是第一次跳2级,此时数目为后面n-2阶跳法数目f(n-2).
因此n级台阶的不同跳法的数目为f(n)=f(n-1)+f(n-2)。这时就可以看做是斐波那契数列了。