算法题目描述
有一对兔子,从出生后第三个月起每个月都生一对兔子,小兔子倡导第三个月后每个月又生一对兔子,假如兔子都不死,问第n(n为正整数)个月的兔子对数为多少?
算法分析
第一个月1对兔子,第二月一对兔子。
第三个月:第二个月的兔子个数再加上新生兔子个数。
新生兔子个数:依据题目:从新生兔子第三个月起才会生兔子,所以第一个月的一对兔子要在第三个月生下一对新兔子;
所以,第三个月总新生兔子数为1;
那么,第三个月总兔子数为第二个月兔子数(1)加上第三个月新生兔子数(即第一个月兔子个数,为1) = 2;
得到规律:新生兔子从第三个月起开始生兔子,且当前月所生兔子数为前第二个月兔子总数。以此类推:从第三个月起每个月兔子个数=前一个月兔子总数 + 前第二个月兔子总数(代表了将要出生的兔子个数)。
公式:
n<=2: 兔子总数=1
n>2: 兔子总数=(n-1)月兔子总数+(n-2)月兔子总数
使用循环解决问题
直接看算法:
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);//接受输入
int n = scanner.nextInt();//获取月数
int[] array = new int[n];//定义数组存储
//第一个月和第二个月
int i1 = 1;
int i2 = 1;
array[0] = i1;
array[1] = i2;
//从第三个月开始
for (int i = 3;i <= 10; i++){
//数组下标要减1
array[i - 1] = array[i - 2] + array[i - 3];//当前月兔子数=上一个月兔子数 + 前第二个月兔子数
}
System.out.println(array[array.length - 1]);//打印输出当前总兔子数:即为最后一个月的兔子数
}
使用反向递归解决问题
由上面的分析我们知道了这个公式:
公式:
n<=2: 兔子总数=1
n>2: 兔子总数=(n-1)月兔子总数+(n-2)月兔子总数
那么基于这个公式我们知道当前月份的兔子总数=往前倒两个月份兔子总数之和,那么当给定一个月份数字,我们可以循环嵌套使用这个公式:
比如:
当月份为4时,那么可以转换为
4月兔子总数=3月兔子总数 + 2月兔子总数
其中三月兔子总数又可以转换为
3月兔子总数=2月兔子总数+1月兔子总数
总式子就变为
4月兔子总数=(2月兔子总数 + 1月兔子总数) + 2月兔子总数。
整体的计算结构我们可以归纳程一个树形结构,如下图:
我们从根节点往下不断进行迭代,每一个当前节点都等于下两个子节点的和,最后把这些加在一起就是最后的结果。
算法:
public class Main {
public static void main(String[] args) {
int n = 10;
System.out.println(func(n));
}
/**
* 递归算法
*/
private static int func(int n){
//第一个月和第二个月特殊处理
if (n == 1 || n == 2){
System.out.println(1);
return 1;
}else {
//三个月以上开始递归计算
// System.out.println("第"+n);
return func(n-1)+func(n-2);
}
}
}
总结
很多时候正向的计算往往带不来太大收益,这时候就可以考虑放过来,逆向运算。