兔群繁殖之谜|青训营笔记

187 阅读3分钟

问题描述

生物学家小 R 正在研究一种特殊的兔子品种的繁殖模式。这种兔子的繁殖遵循以下规律:

  1. 每对成年兔子每个月会生育一对新的小兔子(一雌一雄)。
  2. 新生的小兔子需要一个月成长,到第二个月才能开始繁殖。
  3. 兔子永远不会死亡。

小 R 从一对新生的小兔子开始观察。他想知道在第 A 个月末,总共会有多少对兔子。

请你帮助小 R 编写一个程序,计算在给定的月份 A 时,兔子群体的总对数。

注意:

  • 初始时有 1 对新生小兔子。
  • 第 1 个月末有 1 对兔子:原来那对变成了成年兔子,并开始繁殖。
  • 第 2 个月末有 2 对兔子:原来那 1 对成年兔子,繁殖了 1 对新生的小兔子。
  • 从第 3 个月开始,兔子群体会按照上述规律增长。

题目分析

这是一道数学问题,而且是很经典的斐波拉契数列(又称兔子数列),这道题也是一道很经典的递归算法题(但本题如果用递归会运行超时,所以要使用动态规划)。

现在我们来假设分析一下:

第1个月末有1对兔子,此时兔子已经成熟,下个月就能开始繁殖。

第2个月末有2对兔子,因为上个月剩下的兔子开始繁殖,所以兔子总数变为了1+1对。

第3个月末有3对兔子,因为上个月出生的兔子到了本月才成熟,所以只繁殖了1对兔子,兔子总数为2+1对

第4个月末有5对兔子,因为初始的兔子和第二个月出生的兔子都可以繁殖,所以繁殖了2对兔子,同时第3个月出生的兔子也成熟了。此时兔子总数为3+2对。

第5个月末有8对兔子,因为初始的兔子和第二个月和第三个月出生的兔子都可以繁殖,所以繁殖了3对兔子,同时第4个月出生的兔子也成熟了。此时兔子总数为5+3对。

通过对上述案例分析可得,数列按照{1,1,2,3,5,8...}的顺序排列,我们也可以看出规律。从第3个月开始,这个月的兔子数量等于前两个月的兔子数之和

代码

def solution(A):
    f = [0] * (A + 1)  # 创建一个大小为 A + 1 的数组
    f[0] = f[1] = 1   # 基础情况,f(0) 和 f(1) 都为 1

    for i in range(2, A + 1):
        f[i] = f[i - 1] + f[i - 2]  # 动态规划状态转移

    return f[A]  # 返回第 A 个斐波那契数

我们先创造一个数组用来记录各个月的兔子数量,这样做可以避免重复计算某一月份的兔子数量,从而解决超时问题。

如果本题使用递归算法,我们需要不停地重复计算某一月份的兔子数量。

例如:f(5)=f(4)+f(3)

这时我们需要计算 f(3)=f(2)+f(1) 和 f(4)=f(3)+f(2)

为了计算f(4),我们需要重新计算一遍f(3)

所以当月份很大时,我们会发现会出现重复计算了很多月份,这样子的操作会导致运行超时,所以我们就需要用到动态规划。