Day07 2023/03/06
难度:简单
题目
有一种兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子。例子:假设一只兔子第3个月出生,那么它第5个月开始会每个月生一只兔子。一月的时候有一只兔子,假如兔子都不死,问第n个月的兔子总数为多少?
数据范围:1 ≤ n ≤ 31
输入描述:
输入一个int型整数表示第n个月
输出描述:
输出对应的兔子总数
示例
输入:5
输出:5
思路一
月份 | 兔子数 |
---|---|
第1个月 | 1只兔子 |
第2个月 | 1只兔子 |
第3个月 | 2只兔子 |
第4个月 | 3只兔子 |
第5个月 | 5只兔子 |
可以发现除了前两个月有些特殊外,剩下的月份的兔子数都是它前两个月兔子数之和。因此可得递归公式 ,其实就是斐波那契数列,然后利用此公式逐层递归即可。 如图所示:
唯一缺点:时间复杂度和空间复杂度较高,从上图也可以看出,递归中有,对节点的重复访问,若是题目对复杂度又要求,那也不用着急,下面将介绍一种复杂度较低的解法-迭代的方式。
思路二
-
使用 迭代 的方式,分别设置三种兔子的数量,三个月及其以上的(可生育
k3
),两个月的和一个月的(不可生育k2
和k1
),每过一个月就更新一次,最后返回三种兔子数量之和。 -
其中更新细节为,每过一个月
k3 = k3 + k2; k2 = k1; k1 =k3;
关键点
- 迭代的方式中,注意前1个月比较特殊,更新方式单独处理。
算法实现
c++代码实现1-递归
#include <iostream>
using namespace std;
// 计算n月时的兔子数
int CalNum (int n) { //n为月数
if(n == 1 || n == 2) return 1; //当n为1或者2的时候就跳出当前递归
return CalNum(n - 1) + CalNum(n-2); //本月的兔子数等于前两个月兔子数相加(本质是斐波那契数列)
}
//方法一:递归(斐波那契)
int main () {
int n = 0;
cout << "请输入月份: ";
cin >> n;
cout << "第" << n << "个月兔子数为:" << CalNum(n) << endl;
return 0;
}
- 时间复杂度 --- 遍历整个二叉树(节点数)
- 空间复杂度 --- 递归栈的深度为 n
c++代码实现2-迭代
#include <iostream>
using namespace std;
// 计算n月时的兔子数
int CalNum (int n) { //n为月数
// k1为年龄一个月的兔子,k2为年龄两个月的兔子, k3为年龄三个月的兔子。
int k1 = 0, k2 = 0, k3 = 0;
/ /前1个月比较特殊,先初始化到第1个月的状态
k1 = 1;
k2 = 0;
k3 = 0;
for (int i = 2; i <= n; i++) {
k3 += k2;
k2 = k1;
k1 = k3;
}
return k1 + k2 + k3;
}
// 方法二:迭代
int main () {
int n = 0;
cout << "请输入月份: ";
cin >> n;
cout << "第" << n << "个月兔子数为:" << CalNum(n) << endl;
return 0;
}
- 时间复杂度 --- 循环n-1次,n为月份数
- 空间复杂度 ---常数级空间
总结
- 了解递归,迭代这些基本的算法思想,并学会处理一些特殊的情况。