HJ37 统计每个月兔子的总数

330 阅读2分钟

Day07 2023/01/14

题目链接

难度:简单

题目

有一种兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子。例子:假设一只兔子第3个月出生,那么它第5个月开始会每个月生一只兔子。一月的时候有一只兔子,假如兔子都不死,问第n个月的兔子总数为多少?
数据范围:1 ≤ n ≤ 31 

输入描述:

输入一个int型整数表示第n个月

输出描述:

输出对应的兔子总数

示例

输入:5
输出:5

思路一


月份兔子数
第1个月1只兔子
第2个月1只兔子
第3个月2只兔子
第4个月3只兔子
第5个月5只兔子

可以发现除了前两个月有些特殊外,剩下的月份的兔子数都是它前两个月兔子数之和。因此可得递归公式 f(n)=f(n1)+f(n2)f(n)=f(n−1)+f(n−2),其实就是斐波那契数列,然后利用此公式逐层递归即可。 如图所示:

54CA5BF95CDFE1211880A919591050CD.png

思路二


  • 使用 迭代 的方式,分别设置三种兔子的数量,三个月及其以上的(可生育 k3),两个月的和一个月的(不可生育 k2k1),每过一个月就更新一次,最后返回三种兔子数量之和。

  • 其中更新细节为,每过一个月 k3 = k3 + k2; k2 = k1; k1 =k3;

关键点


  • 迭代的方式中,注意前两个月比较特殊,更新方式单独处理。

算法实现


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;
}

  • 时间复杂度 O(2n)O(2^n) --- 遍历整个二叉树(节点数)
  • 空间复杂度 O(n)O(n) --- 递归栈的深度为 n

c++代码实现2-迭代

// 计算n月时的兔子数
int CalNum (int  n) { //n为月数
    int k1 = 0, k2 = 0, k3 = 0; //k1为年龄一个月的兔子,k2为年龄两个月的兔子, k3为年龄三个月的兔子。
    //前两个月比较特殊,先初始化到第二个月的状态
    k1 = 0; 
    k2 = 1; 
    k3 = 0;
    for (int i = 3; 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;
}
  • 时间复杂度 O(n)O(n) --- 循环n-2次,n为月份数
  • 空间复杂度 O(1)O(1) ---常数级空间

总结

  • 了解递归,迭代这些基本的算法思想,并学会处理一些特殊的情况。