记忆化搜索

一)斐波那契额数

509. 斐波那契数 - 力扣(LeetCode)

解法1:递归

在这个题中,dfs被赋予的使命就是给你一个数N,返回第N个斐波那契额数即可,虽然表面上来看递归函数非常简单,但是如果将递归展开图

记忆化搜索_第1张图片

记忆化搜索_第2张图片

1)这个递归的时间复杂度是很慢的:如图所示,当我们针对于这颗决策树来做深度优先遍历的时候,两个d(3)返回的数都是相同的,但是我们却重复性的计算了两个d(3)的值

2)假设在我们进行深度优先遍历的时候,创建一个备忘录,当计算到左边的第一个绿色的d(3)的时候进行返回,我们将返回值存放到备忘录里面,然后继续进行深度优先遍历,当我们重新遍历到右边的这个d(3)的时候此时就不会继续向下展开,直接将把这个这个d(3)返回

记忆化搜索_第3张图片

记忆化搜索:当在递归的过程中发现,当有重复的问题出现的时候,就可以把把这个完全相同的结果存放到备忘录里面,当继续递归深度优先遍历的时候,直接从备忘录里面取值就可以了,带备忘录的递归,也可以被称之为是一个剪枝;

记忆化搜索_第4张图片

解法2:记忆化搜索

记忆化搜索_第5张图片

1)添加一个备忘录,先找可变参数,将可变参数和返回值存起来就可以了,在上面这个斐波那契额数列里面,可变参数就是N,因为N就是可能在不断变化的,返回值就是第几个斐波那契额数hash,但是在本题中搞一个数组就可以了,可以用数组的下标代表当成第index斐波那契额数的下标,让数组下表对应的值表示第几个斐波那契额数就可以了,还有备忘录初始化的值不能和最终我们计算的结果的值发生冲突,

2)当进行递归每一次返回的时候,将递归的结果存放到备忘录里面

3)在每一次进入到递归的时候,先检查备忘录里面是否已经存在了我们想要的结果,如果存在,直接向上返回结果,也很好地完成了一个剪枝的操作

class Solution {
    int[] hash=new int[31];
//1.如果搞成全局变量的话,那么哈希表中的值都是等于0的,我们在备忘录里面要有一个规则就是备忘录里面的初始值是不能和最终结果的值发生冲突的,当我们去备忘录中找对应的值的时候,需要先判断一下你这个值是否已经被计算过了,如果你的备忘录里面本身就存在着一个值X,我还没计算到第一个位置呢,都已经存在值X
//2.所以在初始化备忘录的时候,我们要初始化成这个递归函数永远都不可能计算出来的返回值
    public int fib(int n) {
        Arrays.fill(hash,-1);
        return dfs(n);
    }
    public int dfs(int n){
//1.在进行进入到递归的时候,先去备忘录中找一下有没有结果,如果没有才继续向下递归
        if(hash[n]!=-1) return hash[n];
        if(n==0||n==1){
           hash[n]=n;
           return n;
        } 
//2.返回之前现将结果存放到备忘录里面
        hash[n]=dfs(n-1)+dfs(n-2);
        return hash[n];
    }
}
解法3:动态规划

1)确定一个状态标识:对应的就是dfs函数代表什么含义,dfs函数的含义就是给定一个数n,返回第n个斐波那契额数,所以这个n是一个可变参数,你给几,就返回第N个斐波那契数

dp[i]第i个斐波那契额数;

2)根据状态标识推到状态转移方程:对应的就是dfs函数的函数体,在dfs函数中是如何调用dfs函数的,dp[i]=dp[i-1]+dp[i-2]

3)初始化:递归出口,因为递归出口是不参与dfs(n-1)和dfs(n-2)的

你可能感兴趣的:(算法)