题目简述
兔子的繁殖规律可以总结如下:
- 第一个月开始只有一对小兔子。
- 第二个月这对小兔子成为成年兔子并开始繁殖,所以仍然只有一对兔子。
- 从第三个月开始,每对成年兔子每个月都会生育一对新的小兔子(一雌一雄),而新生的小兔子需要一个月成长才能开始繁殖。 输入:
A:表示月份数
输出:
ans:表示第 A 个月末兔子的总对数
代码思路
按照题意,我们可以推出以下:
-
幼仔对数=前月成兔对数
-
成兔对数=前月成兔对数+前月幼仔对数
-
总体对数=本月成兔对数+本月幼仔对数
可以看出幼仔对数、成兔对数、总体对数都构成了一个数列。这个数列有关十分明显的特点,那是:前面相邻两项之和,构成了后一项。
这就是著名的斐波那契数列,又称“兔子数列”。
斐波纳契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)
用递归方法实现:
定义一个递归函数 calculate_rabbit_pairs_recursive(month),该函数返回第 A 个月末兔子的总对数。
基本情况:
- 如果月份为 1,返回 1 对小兔子。
- 如果月份为 2,返回 1 对成年兔子和 1 对小兔子,共 2 对兔子。
递归步骤:
- 对于大于 2 的月份,兔子总对数等于上个月成年兔子对数和小兔子对数之和。成年兔子对数则等于上个月的小兔子对数,小兔子对数等于上个月的成年兔子对数。
递归调用函数并返回总对数即可。
def calculate_rabbit_pairs_recursive(A):
if A == 1:
return 1
elif A == 2:
return 2
else:
return calculate_rabbit_pairs_recursive(A - 1) + calculate_rabbit_pairs_recursive(A - 2)
时间复杂度分析:
-
每一次递归调用都会产生两个新的递归调用,形成指数级别的递归树结构。
-
每一层的递归调用会产生指数级别的子问题。
时间复杂度可以用指数形式表示为 O(2^N),其中 N 是月份 A。
用非递归方法实现:
- 初始化两个变量
adult_pairs和baby_pairs分别表示成年兔子对数和小兔子对数。 - 对于月份 A 大于等于 3 的情况,我们使用循环递推计算每个月的兔子对数。
- 每个月的新成年兔子对数等于上个月的成年兔子对数加上上个月的小兔子对数,即
new_adult_pairs = adult_pairs + baby_pairs。 - 每个月的新小兔子对数等于上个月的成年兔子对数,即
baby_pairs = adult_pairs。 - 更新成年兔子对数为新的成年兔子对数,即
adult_pairs = new_adult_pairs。 - 循环直到计算到第 A 个月为止,最后返回成年兔子对数和小兔子对数之和即为总对数。
def calculate_rabbit_pairs(A):
if A == 1:
return 1
elif A == 2:
return 2
else:
adult_pairs = 1 # 初始成年兔子对数
baby_pairs = 0 # 初始小兔子对数
for _ in range(3, A + 1):
new_adult_pairs = adult_pairs + baby_pairs # 新的成年兔子对数为上个月的成年兔子和小兔子总数
baby_pairs = adult_pairs # 新的小兔子对数为上个月的成年兔子对数
adult_pairs = new_adult_pairs # 更新成年兔子对数
return adult_pairs + baby_pairs
时间复杂度分析:
-
对于每个月份 A,我们只需进行一次循环迭代来计算兔子的总对数。
-
每次迭代的计算量是常数级别的,不会随着月份 A 的增加而呈指数级增长。
因此,整体的时间复杂度是线性的,即 O(N),其中 N 是输入的月份 A
相比之前的递归方法,这种非递归方法的时间复杂度更低,更高效。