斐波那契及青蛙跳台阶@剑指offer

本文详细解析了斐波那契数列的多种应用场景,包括青蛙跳台阶、变态跳台阶及矩形覆盖等问题,提供了递归、动态规划等算法实现,并深入探讨了算法效率。

题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。 n<=39

思路分析
斐波那契数列:0,1,1,2,3,5,8,13…满足f(n)=f(n-1)+f(n-2),很显然可以用递归来做。代码如下一。

法二:动态规划。

代码实现

#法一:递归实现
def Fibonacci(n):
    if n in [0, 1]:
        return n
    if n >= 2:
        return Fibonacci(n - 1) + Fibonacci(n - 2)

递归实现代码简单易懂,但是当n取值较大时,计算起来比较麻烦,浪费时间和内存空间。
如计算F(6)=F(5)+F(4)=(F4+F3)+(F3+F2)=(F3+F2)+(F2+F1)+(F2+F1)+(F1+F0)=(F2+F1)+(F1+F0)+(F1+F0)+F1+(F1+F0)+F1+F1+F0
这样计算F1和F0的次数非常的多,当n取值较大时,需要花很长时间。不建议使用。

因为在实际的斐波那契数列中,每一项的取值都与前两个相关,所以考虑选用循环的方法来做,每次记住前两个数值,为下一次使用做准备。
在这种方法中,需要把最前面的几项单独列出来,(记住要考虑N=0的情况),后面有规律的采用循环的方法。

#二。循环
def Fibonacci(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    if n == 2:
        return 1
    if n >= 3:
        s = []*n
        s.append(0)
        s.append(1)
        s.append(1)
        for i in range(3, n+1):  # range左闭右开
            s.append(s[i - 1] + s[i - 2])
        return s[n]
#二,循环
def Fibonacci(n):
    if n in [0,1]:
        return n
    if n >= 2:
        first = 0
        second = 1
        third = 0
        for i in range(2, n+1): #注意要取n+1, 因为range()左开右闭
            third = first + second
            first = second
            second = third
        return third

把相邻的三个数first, second, third看做一组,每一次循环都向后移动,最后返回三个数中的最后一个。

#二 动态规划
def Fibonacci2(n):
    f = 0  #F(n)
    g = 1  #F(n+1)
    while n > 0:
        n -= 1
        g += f  #g = F(n)+F(n+1)
        f = g - f #f = F(n+1)
    return f #F(n), F(n+1),F(n)+F(n+1)

在这种解法中,利用了动态规划的思想。把f理解为F(n), g理解为F(n+1),所以每次的结果只和前两个有关,节省了存储空间。

青蛙跳台阶

题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

思路分析
假设青蛙要跳到n级,那么他最后一次可能跳2级,也可能跳1级。因此分成这两种情况考虑。
青蛙跳n级,有F(n)种方法,那么如果最后一次跳1级,前n-1级有F(n-1)种。如果最后一次跳2级,前n-2级有F(n-2)种。
因此,F(N)=F(n-1)+F(n-2),这也是一个斐波那契数列。
先考虑最前面几项,
n=0,F(0)=0;
n=1,F(1)=1;
n=2,F(2)=2; (1+1, 2)
n=3,F(3)=3 (1+2, 2+1, 3)
n=4,F(4)=5 (1+1+1+1, 1+1+2,1+2+1, 2+1+1, 2+2 )
所以,该斐波那契数列为,0,1,2,3,5
采用循环的方法实现

代码如下

def Fibonacci(n):
    if n in [0, 1, 2]:
        return n
    if n >= 3:
        first = 1
        second = 2
        third = 0
        for i in range(3, n+1):
            third = first + second
            first = second
            second = third
        return third

变态跳台阶

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

思路分析
和前一个题目类似,F(n)=F(n-1)+F(n-2)+F(n-3)+…+F(n-n)
考虑边界值,当一次跳n阶时,一共有1种跳法,即F(n-n)=1
当一次跳n-1阶时,有两种n-1, 1,F(n-(n-1))=2
所以,F(n)=F(n-1)+F(n-2)+F(n-3)+…+2+1
F(n-1)=F(n-2)+F(n-3)+…+2+1
两式相减,F(n)-F(n-1)=F(n-1)
F(n)=2*F(n-2)
由此得到递归的规律。

代码实现

def jumpFloor2(number):
    if number in [0, 1]:
        return number
    if number >= 2:
        first = 1
        second = 0
        for i in range(2, number + 1):
            second = 2 * first
            first = second
        return second

变态跳台阶2

题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上m级。求该青蛙跳上一个n级的台阶总共有多少种跳法。(m<n)

思路分析
和前一个题目类似,F(n)=F(n-1)+F(n-2)+F(n-3)+…+F(n-m);
F(n-1)=F(n-2)+F(n-3)+F(n-4)+…+F(n-m-1)
所以,F(n)-F(n-1) = F(n-1)-F(n-m-1)
F(n) = 2* F(n-1)- F(n-m-1)
得到了相邻项的关系。

代码实现

矩形覆盖

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

思路分析
小矩形放置的时候有两种方法,一种是横向放置,一种是竖向放置。
大矩形为2行n列,当小矩形竖向放的时候,剩余n-1列有F(n-1)种放法;
当小矩形横向放置时,也就确定了下方两个空格的放法,剩余n-2列有F(n-2)种放法,因此, F(n)=F(n-1)+F(n-2)
确定边界值:n=1, F=1;
n=2, F=2
n=3, F=3

代码实现

def rectCover(number):
   ans = [0, 1, 2]:
    if number >= len(ans):
        ans.append(ans[-1] + ans[-2])
    return ans[number]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值