递归算法Q1——斐波那契数列
/*
有一对兔子,从出生后第3个月起,每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子。
假如兔子都不死,求第n个月兔子对数
关于斐波那契数列的兔子繁殖问题其实如下:
实际月份 1 2 3 4 5 6 7 8
幼仔对数 1 0 1 1 2 3 5 8
成兔对数 0 1 1 2 3 5 8 13
总体对数 1 1 2 3 5 8 13 21
幼仔对数=前月成兔对数
成兔对数=前月成兔对数+大前月幼仔对数
总体对数=本月成兔对数+本月幼仔对
*/
package 递归;
public class 斐波那契数列 {
//上楼梯的递推式与斐波那契数列一样也为f(n)=f(n-1)+f(n-2)
//n fib(n)
//1 1 1 2 3
//2 1 2 3 5
//3 2
//4 3
//5 5
/**递归
* 存在重复计算
* @param n
* @return
* 时间复杂度:O(2^n) 尝试按照T(n)=T(n-1)+T(n-2)+O(1)去推 失败了
* 空间复杂度:对应搜索二叉树 O(n)
*/
int fib0(int n) {
if(n<=2) return 1;
return fib0(n-2)+fib0(n-1);
}
/**
* @param n
* @return
* 用数组fib存储计算过的fib(n)值 每一个值对应的fib(n)只被计算一次
* 时间复杂度:O(n)
* 空间复杂度:O(n)
*/
int fib1(int n) {
//规模小于2直接返回值
if(n<=2) return 1;
int [] nums=new int[n+1];
return fib1(n,nums);
}
/**
* @param n
* @param nums
* @return
* 空间复杂度:O(n)
* 时间复杂度:O(n)
*/
int fib1(int n,int []nums) {
if(n<=2) return 1;//递归出口
if(nums[n]==0) {//说明n对应的fib值没有计算过
nums[n]=fib1(n-1,nums)+fib1(n-2,nums);
}
return nums[n];
}
int fib2(int n) {
if(n<=2) return 1;
int []fib=new int[n+1];
fib[1]=fib[2]=1;
for(int i=3;i<=n;i++) {
fib[i]=fib[i-1]+fib[i-2];
}
return fib[n];
}
//0// 1 1 3 3
//1// 1 2 2 5
/**
* @param n
* @return
* 每次运算只需用到数组中的两个元素 所以使用滚动数组
* 时间复杂度:O(n)
* 空间复杂度:O(1)
*
*/
int fib3(int n) {
if(n<=2) return 1;
int []fib=new int[n];
fib[0]=fib[1]=1;
for(int i=3;i<=n;i++) {
//i=3 1 0 1
//4 0 1 0
//5 1 0 1
fib[i&1]=fib[(i-1)&1]+fib[(i-2)&1];
}
return fib[n&1];
}
//两变量
int fib4(int n) {
if(n<=2) return 1;
int first=1;
int second=1;
for(int i=3;i<=n;i++) {
// f(1)+f(2)
first=first+second; //2 3 5
second=first-second; //1 2
}
return first;
}
//三变量
int fib5(int n) {
if(n<=2) return 1;
int first=1;
int second=1;
int third=0;
for(int i=3;i<=n;i++) {
third=first+second;
first=second;
second=third;
}
return third;
}
public static void main(String[] args) {
斐波那契数列 a=new 斐波那契数列();
System.out.println(a.fib0(6));
System.out.println(a.fib1(6));
System.out.println(a.fib2(6));
System.out.println(a.fib3(6));
System.out.println(a.fib4(6));
System.out.println(a.fib5(6));
}
}