1. 问题描述:求解出斐波拉契数列的第n项
2. 对于斐波拉契数列,我们都不陌生,求解的方法也有很多,可以使用普通的递归f(n) = f(n - 1) + f(n - 2)来求解,可以使用矩阵的幂运算来进行求解,可以使用闭式解法来进行推导求解,还可以使用记忆性的递归来进行实现
下面使用记忆型的递归来解决,对于通项公式f(n) = f(n - 1) + f(n - 2)我们可以发现假如使用深度优先搜索的话(普通的递归)存在着重复子问题的重复求解, 假如再一次进行相同的子问题递归求解那么数据量大的话就会导致耗时非常大
比如求解f(5),那么求解的过程如下:
可以从图中看出,f(3)就是重复的子问题,左边求解f(3)的时候然后递归下去的时候再一次求解到f(3)那么就造成了重复子问题的重复求解了,这个时候就要使用到我们的记忆型的递归了(f(2)也是重复的子问题)
记忆型的递归与普通的递归差不多,求解的过程都是一样的,只是求解的过程中需要记录中间的值,当调用完成之后我们使用一个一维数组来进行记录,(具体要看题目具体的要求,也可以使用其他的数据结构比如二维数组来进行记录),采用的策略是递归之前先进行查询,看一下之前是否之前计算过这个子问题,查询之后发现之前计算过那么直接返回就可以了,就不用再继续搜索下去了,假如没有计算过那么就计算,计算之后那么就把这个值保存起来,方便以后查询
策略:递归之前先查询,递归之后要保存
比如像上面的计算f(5)的过程调用f(2)结束之后那么f(2)的结果就保存起来了,返回f(3)的时候就把f(3)保存起来那么后面递归搜索的时候发现之前算过直接返回
3. 具体的代码如下:
import java.util.Scanner;
public class Main{
//使用一维数组来进行记录
static int rec[];
static int v1 = 0;
static int v2 = 0;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
rec = new int[n];
//要先进行初始化
rec[0] = 1;
rec[1] = 1;
int res = f(n - 1);
System.out.println(res);
for(int i = 0; i < n; i++){
System.out.print(rec[i] + " ");
}
sc.close();
}
private static int f(int n){
if(n == 0 || n == 1) return 1;
if(rec[n] > 0){
//通过输出语句可以看到的确在求解重复子问题的时候查询之后发现之前求解过那么就会直接返回了
System.out.println(rec[n]);
return rec[n];
}else{
v1 += f(n - 1);
//左边已经把f(n - 1)计算出来了所以v2直接加上f(n - 2)就是当前调用f(n)结束之后f(n)的值了
v2 = v1 + f(n - 2);
//调用完之后那么进行f(n)的值的记录
rec[n] = v2;
return v2;
}
}
}