什么是斐波那契数列
从第三个元素开始,每个元素的值等于前两个元素的和
本质其实也是一个递归操作,话不多说我们直接上代码。
public class Fibinacci {
public int f(int n) {
if(n==0){
return 0;
}
if(n==1){
return 1;
}
int x=f(n-1);
int y=f(n-2);
return x+y;
}
}
上述代码不难理解,我们接着继续分析
斐波那契数列的时间复杂度
假设我们需要求得f(5)的值,思路如下
我们需要一步一步往前递推,我们将递推得到的值转成节点,连接起来形成二叉树
我们发现了一个规律
f(n)需要执行的递归调用次数也为一个斐波那契数列
斐波那契递归的优化方法
我们看到常规的斐波那契数列需要的时间复杂度为指数函数,效率很低,我们试着去优化
我们看到在之前执行递归操作的时候有很多重复操作,优化的思路也很简单,就是针对重复操作进行优化,将之前已经计算过的数据存入数组里面。
数组0索引的值对应f(0),1对应f(1),以此类推,如下
思路如下
我们先写一个总方法,在里面生成一个数组,通过递归方法将计算斐波那契数列得到的对应值存入每日一个数组里面,在创建数组的时候,我们将它第一,二个元素设置为0,1,其他元素设置成-1,这样子我们在递归方法里面再设置一个if判断,如果当前调用的数组元素值已经不为-1,直接返回就好,不用再一直递归下去,节约效率。所以在参数设置中,我们需要再多传入一个初始数组,如下:
public class Fibinacci {
public static int fib(int n) {
int[] cache = new int[n+1];
Arrays.fill(cache, -1);//[-1,-1,-1,-1,-1]
cache[0] = 0;
cache[1] = 1;//[0,1,-1,-1,-1]
return f(n,cache);
}
public static int f(int n,int []cache) {
if(cache[n] != -1) return cache[n];
int x=f(n-1,cache);
int y=f(n-2,cache);
cache[n]=x+y;
return cache[n];
}
}
斐波那契数列的变体问题:
兔子问题:
我们从最后一个月进行分析
我们设第n个月的兔子数为f(n)
f(6)=f(5)+第五个月产生的兔子。
第五个月成熟的兔子=f(4)......
f(6)=f(5)+f(4);
本质上是斐波那契数列,我们接下来实现代码
我们只需要将创建的斐波那契数列的前两个元素改为1,1即可。
public class Fibinacci2 {
public static int fib(int n) {
int[] cache = new int[n+1];
Arrays.fill(cache, -1);//[-1,-1,-1,-1,-1]
cache[0] = 1;
cache[1] = 1;//[1,1,-1,-1,-1]
return f(n,cache);
}
public static int f(int n,int []cache) {
if(cache[n] != -1) return cache[n];
int x=f(n-1,cache);
int y=f(n-2,cache);
cache[n]=x+y;
return cache[n];
}
}
变体2-青蛙爬楼梯
我们来看分析:
不难发现,其实每一次的规律本质上也是斐波那契数列
我们依然该写数组的首两个元素即可
public class Fibinacci2 {
public static int fib(int n) {
int[] cache = new int[n+1];
Arrays.fill(cache, -1);//[-1,-1,-1,-1,-1]
cache[0] = 1;
cache[1] = 2;//[1,2,-1,-1,-1]
return f(n,cache);
}
public static int f(int n,int []cache) {
if(cache[n] != -1) return cache[n];
int x=f(n-1,cache);
int y=f(n-2,cache);
cache[n]=x+y;
return cache[n];
}
}