蓝蓝计算机考研算法-day07统计每个月兔子总数

141 阅读2分钟

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只兔子

可以发现除了前两个月有些特殊外,剩下的月份的兔子数都是它前两个月兔子数之和。因此可得递归公式 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;

关键点


  • 迭代的方式中,注意前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;
}

  • 时间复杂度 O(2n)O(2^n) --- 遍历整个二叉树(节点数)
  • 空间复杂度 O(n)O(n) --- 递归栈的深度为 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;
}

  • 时间复杂度 O(n)O(n) --- 循环n-1次,n为月份数
  • 空间复杂度 O(1)O(1) ---常数级空间

总结

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