这道题目涉及计算在第 ( A ) 个月底时兔子的总对数,符合类似斐波那契数列的递推关系。题目的繁殖规律可以总结如下:
- 初始状态有一对小兔子。
- 在第一个月结束时,最初的一对小兔子会长大成为成年兔。
- 从第二个月开始,每对成年兔子每月都会繁殖一对小兔子。
于是可以得到递推关系:
- ( f(1) = 1 )
- ( f(2) = 2 )
- ( f(n) = f(n - 1) + f(n - 2) ) (从第三个月开始)
为什么递归法会超时
递归法会导致超时的问题主要是因为:
-
大量的重复计算:在递归方法中,例如
f(n) = f(n - 1) + f(n - 2),计算f(n - 1)和f(n - 2)需要分别计算f(n - 2)、f(n - 3)等,导致同一个子问题会被重复计算多次。这种重复计算会导致指数级的复杂度,即 ( O(2^n) )。 -
栈溢出风险:递归方法会不断压栈,当输入较大时(例如 ( A = 50 )),调用栈深度可能超过 Python 的默认限制,导致栈溢出错误。
动态规划的迭代解法
为避免递归的重复计算问题,可以使用动态规划的迭代法,用两个变量保存前两个月的兔子对数来逐步求解下一个月的数量。这种方法的时间复杂度为 ( O(n) ),空间复杂度为 ( O(1) ),能够高效处理较大输入
通过迭代法解决了这个兔子繁殖问题,相比于递归方法,这种方法避免了重复计算,使得代码更高效。我们来逐行分析代码:
def solution(A):
# 边界条件
if A == 1:
return 1
if A == 2:
return 2
首先,处理了特殊情况:
- 当 ( A = 1 ) 时,返回 1。即第一个月只有一对兔子。
- 当 ( A = 2 ) 时,返回 2。即第二个月有两对兔子,一对成年的兔子和一对刚出生的小兔子。
这两种情况是递归关系的基础,直接返回结果避免了后续的循环。
prev1, prev2 = 2, 1
这里定义了两个变量 prev1 和 prev2,分别表示前两个月的兔子对数:
prev1表示上一个月的兔子对数(即 ( f(n-1) ))。prev2表示上上个月的兔子对数(即 ( f(n-2) ))。
初始化为 prev1 = 2 和 prev2 = 1 是因为:
- 在 ( A = 2 ) 时,兔子对数是 2,对应
prev1的初始值。 - 在 ( A = 1 ) 时,兔子对数是 1,对应
prev2的初始值。
for _ in range(3, A + 1):
current = prev1 + prev2
prev2 = prev1
prev1 = current
这里的 for 循环从 3 开始遍历到 ( A ),每次计算下一个月的兔子对数:
- 计算当前月兔子对数:
current = prev1 + prev2。根据题目规律,当前月的兔子对数等于前两个月的兔子对数之和,这相当于斐波那契数列的递推关系 ( f(n) = f(n-1) + f(n-2) )。 - 更新前两个月的对数:
prev2 = prev1:将上个月的兔子对数prev1更新为prev2,以便在下一轮循环中使用。prev1 = current:将当前月的兔子对数current更新为prev1,以便在下一轮循环中使用。
通过这种方式,每次循环都能计算出下一个月的兔子对数,直至第 ( A ) 个月。
return prev1
最终返回 prev1,即第 ( A ) 个月的兔子对数。
为什么这种方法比递归快
递归方法会在每次调用时重新计算 f(n-1) 和 f(n-2),这样会导致很多重复计算。例如,当计算 f(50) 时,递归方法会计算 f(49) 和 f(48),而 f(49) 本身又会计算 f(48) 和 f(47),这样导致同一个子问题被多次计算。
而在迭代代码中,通过使用 prev1 和 prev2 保存前两个月的结果,避免了重复计算,每个月的兔子对数只需计算一次。因此,这种迭代方法的时间复杂度是线性的 ( O(n) ),比递归的指数级复杂度 ( O(2^n) ) 要高效得多,能够在合理的时间内处理大数
完整代码
def solution(A):
# Edit your code here
if A == 1:
return 1
if A == 2:
return 2
prev1, prev2 = 2, 1
for _ in range(3, A + 1):
current = prev1 + prev2
prev2 = prev1
prev1 = current
return prev1
if __name__ == "__main__":
# Add your test cases here
print(solution(5) == 8)
print(solution(1) == 1)
print(solution(15) == 987)
print(solution(50) == 20365011074)