【剑指offer学习记录】10-斐波那契数列

10-斐波那契数列

题目:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。n<=39

n=0时,f(n)=0 n=1时,f(n)=1 n>1时,f(n)=f(n-1)+f(n-2)

题目解析

斐波那契数列是一道经典的递归解法的题目。

此题有两种思路,一种是正常的递归方法,但是会产生很多的冗余项,会有很多重复计算项;

因此第二种思路就是按照斐波那契数列的递归计算的状态树,从下往上根据小项来推大项,这样每一项只用计算一次,这种方法代码实现上体现为循环。

代码实现

 1  #方法一:递归法
 2  class Solution:
 3      def Fibonacci(self,n):
 4          if n<=0:
 5              return 0
 6          else n==1:
 7              return 1
 8          return self.Fibonacci(n-1) + self.Fibonacci(n-2)
 9      
10  # 方法二:自下而上的循环方法
11  class Solution:
12      def Fibonacci(self, n):
13          res = [0,1]
14          if n<2:
15              return res[n]
16          MinusOne = 1
17          MinusTwo = 0
18          Nsum = 0
19          for i in range(2, n+1):
20              Nsum = MinusOne + MinusTwo
21              MinusTwo = MinusOne
22              MinusOne = Nsum
23          return Nsum   

 

拓展题目一:跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

题目解析

遇到这种有多个状态,而求得结果是多个固定状态组合的结果,都可以考虑递归方法。

在此题中,可以把n级台阶的跳法看做函数f(n)。

假设有n个台阶,则跳第一阶的时候,有两个状态:

第一个状态是跳一阶,剩余n-1,则此时的跳法有f(n-1)种,依赖于后n-1个台阶的跳法

第二个状态是跳二阶,剩余n-2,则此时的跳法有f(n-2)种,依赖于后n-2个台阶的跳法

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

代码实现

 
 1 class Solution:
 2      def JumpFloor(self, number):
 3          if number == 1:
 4              return 1
 5          if number == 2:
 6              return 2
 7          small, big = 1,2
 8          #这里要注意,因为是跳台阶,到第n的时候是不会动的,所以不包含n,和斐波那契数列求和是不同的
 9          for i in range(2, number):
10              sum_i = small + big
11              small = big
12              big = sum_i
13          return sum_i

 

拓展题目二:跳台阶进阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

解题方法

对于此类状态很多的情况,也是先将所有的状态列出来。

首先是f(n)情况,f(n) = f(n-1) + f(n-2) + ... +f(1) + f(0)

再看f(n-1)情况,f(n-1) = f(n-2) + f(n-3) + f(n-4) + ... + f(1) + f(0)

将f(n) - f(n-1),有f(n) - f(n-1) = f(n-1),所以有f(n) = f(n-1),其中n>0,f(1) = 1

所以可以归纳到f(n) = 2^ (n-1)

代码实现

对应的实现有两种,一种是f(n) = f(n-1),一种是直接使用得到的公式f(n) = 2^ (n-1)

 
 1 class Solution:
 2      def Jump1(self, number):
 3          if number<=0:
 4              return 0
 5          return 2**(number-1)
 6      def Jump2(self, number):
 7          if number<=0:
 8              return 0
 9          if number == 1:
10              return 1
11          return 2*self.Jump(number - 1)

 

10-扩展题目三:矩形覆盖

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2n的大矩形,总共有多少种方法?

题目解析

此题依旧是斐波那契数列解题的思路,首先根据某一状态进行具体分析,然后找到状态的递推规律。

首先假设是2*8的矩阵,那么可以将单元矩形竖着一列放一个,则剩余部分为2*7的矩阵。

如果是将单元矩阵横着放,则要横着放两个,然后剩余部分为2*6矩阵。

根据这种转换状态,可以知道,f(8) = f(7) +f(6)

代码实现

 1  class Solution: 
 2      def rectCover(self, number):
 3          if number<=0:
 4              return 0
 5          if number == 1:
 6              return 1
 7          if number == 2:
 8              return 2
 9          small, big = 1, 2
10          #注意这里到f(n)的话也是要求解的,因为对于n的情况也要覆盖,所以要包含n,因此边界是n+1不包含
11          for i in range(3, number + 1):
12              sum_i = small + big
13              small = big
14              big = sum_i
15          return big

 


             
posted @ 2020-07-15 20:38  szxyx  阅读(164)  评论(0编辑  收藏  举报