学习方法与心得
题目解析
问题描述
这道题是经典的斐波那契数列问题,描述了一个兔子繁殖模型:
- 每对兔子第一个月无法繁殖。
- 从第二个月起,每对兔子会生下一对新兔子。
- 假定所有兔子永远不会死亡,并且每对兔子都是一雌一雄。
例子解析:
- 第1个月:只有一对兔子,输出为
1。 - 第2个月:繁殖了1对新兔子,总共有
2对兔子。 - 第3个月:第一对兔子繁殖出1对新兔子,总共
3对兔子。 - 第4个月:第一对兔子繁殖1对,第二对也开始繁殖,总共
5对兔子。
观察规律发现,每个月的兔子总数是前两个月兔子数量的和,这与斐波那契数列完全一致。
解题思路
题目本质是求解斐波那契数列的第n项:
- 第1个月:兔子数量为
1。 - 第2个月:兔子数量为
2。 - 第
n个月:兔子数量等于前两个月兔子数量之和。
直接使用动态规划的思想:
- 用两个变量记录前两个月的兔子数量,避免使用递归引入栈溢出问题。
- 每次计算当前月的兔子数量,并更新前两个月的值。
- 这种实现方式时间复杂度为
O(n),空间复杂度为O(1),非常高效。
代码实现
以下是完整的代码实现:
public class Main {
public static long solution(int A) {
// 如果输入的月份是1或2,直接返回对应的兔子对数
if (A == 1) return 1;
if (A == 2) return 2;
// 初始化前两个月的兔子对数
long prev1 = 1; // 第1个月的兔子对数
long prev2 = 2; // 第2个月的兔子对数
long current = 0; // 当前月的兔子对数
// 从第3个月开始计算,直到第A个月
for (int i = 3; i <= A; i++) {
// 计算当前月的兔子对数
current = prev1 + prev2;
// 更新前两个月的兔子对数
prev1 = prev2;
prev2 = current;
}
// 返回第A个月的兔子对数
return current;
}
public static void main(String[] args) {
// 添加你的测试用例
System.out.println(solution(1) == 1L);
System.out.println(solution(5) == 8L);
System.out.println(solution(15) == 987L);
System.out.println(solution(50) == 20365011074L);
}
}
核心算法分析
1. 时间复杂度
由于我们只需要遍历一次1到n的范围,时间复杂度为O(n),其中n是输入的月份。
2. 空间复杂度
只使用了prev1、prev2和current三个变量记录状态,不需要额外的存储空间,因此空间复杂度为O(1)。
3. 适用场景
这种实现适用于范围较大的斐波那契数列计算(如本题的n <= 75),相比递归方法不会造成栈溢出问题。
知识总结
通过本题,我学习了以下知识点:
-
斐波那契数列与动态规划
- 斐波那契数列是一种典型的递归关系,通过优化存储方式可以避免重复计算。
- 动态规划思想通过记录中间状态(即前两个月的兔子数量)来降低计算量。
-
循环替代递归
- 递归实现斐波那契数列非常直观,但容易因栈深度限制而失败。
- 使用循环结合变量替换的方式,可以有效解决这一问题。
-
变量的滚动更新
- 动态规划中,很多问题可以用变量滚动更新的方式优化空间复杂度。
学习计划
1. 每天刷1-2道经典动态规划题目
结合豆包MarsCode AI的题库,从简单的斐波那契数列开始,逐步挑战更复杂的问题,如最长公共子序列等。
2. 梳理动态规划的经典模型
动态规划问题往往具有重复子问题的特性,按照斐波那契数列、背包问题等模型分类学习,能更高效掌握。
3. 错题总结与优化
记录每次出错的题目,分析原因后重新实现,重点关注算法优化和边界条件处理。
工具运用
-
豆包MarsCode AI 的解析功能
- 使用解析功能了解问题的核心思路和高效解法,尤其是动态规划的递推公式与代码实现。
-
与其他资源结合
- 动态规划相关的入门书籍和视频课程,帮助理解递推公式的推导过程。
-
测试与验证
- 利用豆包MarsCode AI提供的测试数据集,验证代码的正确性和性能,逐步优化代码实现。
学习建议
-
从简单模型开始学习
动态规划入门可以从斐波那契数列、爬楼梯问题等简单模型入手,逐步提高难度。 -
注重思路而非代码
在解题时,优先理解问题的递推关系和动态规划公式,再转化为代码实现。 -
持续练习,积累经验
动态规划问题需要不断练习才能熟练掌握,持之以恒是关键。
通过这道题目,相信每位学习者都能在动态规划的学习中迈出扎实的一步!