Day07 2023/03/06
难度:简单
题目
有一种兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子。例子:假设一只兔子第3个月出生,那么它第5个月开始会每个月生一只兔子。一月的时候有一只兔子,假如兔子都不死,问第n个月的兔子总数为多少?
数据范围:1 ≤ n ≤ 31
输入描述:
输入一个int型整数表示第n个月
输出描述:
输出对应的兔子总数
示例
输入:5
输出:5
复制代码
思路一
可以发现除了前两个月有些特殊外,剩下的月份的兔子数都是它前两个月兔子数之和。因此可得递归公式 f(n)=f(n−1)+f(n−2),其实就是斐波那契数列,然后利用此公式逐层递归即可
代码:
static int fib(int n){
if (n == 1 || n == 2)return 1;
return fib(n-1)+fib(n-2);
}
- 时间复杂度 :O(2n) --- 遍历整个二叉树(节点数)
- 空间复杂度 :(n) --- 递归栈的深度为 n
思路二:
利用动态规划来求斐波那契数列,其实就是用空间换时间,因为求斐波那契数列会重复求子问题,例如要求 fib(5)就要求fib(4)和fib(3),如果在此之前我们就把fib(4)和fib(3)的数给存在数组里面,就可以加快求解速度。
代码:
static int fib2(int n){
int dp[] = new int[n+1];
dp[1] = 1;
dp[2] = 1;
for (int i = 3;i <= n;i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
同样是将原问题划分为一个个子问题,通过子问题的求解得到原问题的解。但不同的是子问题求解过程中对解的保存,上述求F(6)时直接寻秩找到F(5)和F(4)的解即可得出,而F(4)和F(5)的解向前递推,从而避免大量的重复计算。可以比较下上述两者的求解速度。
可以用上述两种办法分别求fib(1000)会发现速度的差距;