1、斐波那契数列举例 + 记忆化搜索解读
对于斐波那契数列这题可以用多种方法解答:
1、循环。2、递推。3、递归。4、dp。5、记忆化搜索。6、矩阵快速幂。
循环和递推就不说了。矩阵快速幂这里也不说。
解法一:首先用递归来写:
class Solution {
public:
int fib(int n) {
return dfs(n);
}
int dfs(int n)
{
if(n == 0 || n == 1) return n;
return dfs(n-1) + dfs(n-2);
}
};
对于递归方式,时间复杂度是比较高的,下面来分析一下:
对于求dfs(5)的话,由递归展开图来看,是一颗近似完全二叉树的递归展开图,那么这里的图上每个结点都要去调用,时间复杂度其实就在O(2^5)。
那么本题递归的时间复杂度就在O(2^N),空间复杂度在O(N)。
指数级的时间复杂度是非常恐怖的。
但是对于这个决策树来看,我们递归左边的时候:
已经计算了d(3),但是在递归右边的时候还是会去计算d(3),即相同的问题,递归时会重复计算,这就是造就时间复杂度如此之高的原因。
同样,左边计算了d(2),右边还是会去计算d(2)。
对于这种递归途中,出现完全相同的子问题时,如果我们已经计算过某一个子问题,并且记录这个值,那么在遇到这个相同的子问题时,我们就可以直接得到值,并不需要再次调用递归。这就是记忆化搜索。
解法二:记忆化搜索:
什么是记忆化搜索:带“备忘录”的递归。就是每次递归完成的时候,记录一下当前递归情况的值。
如何实现记忆化搜索:
1、添加一个“备忘录”-->备忘录内呈现一一对应的关系。<可变参数,返回值>
2、递归结束返回之前,将结果放入备忘录。
3、每次递归开始的时候,往备忘录里瞅一瞅。看看有没有已经存储当前递归结果。
//记忆化搜索
class Solution
{
int memory[31];//备忘录一般用哈希表,这里用数组也行
public:
int fib(int n)
{
//备忘录开始前,里面存的值不能是递归过程中会出现的结果,那样就无法判断是否计算过那个结果
memset(memory,-1 ,sizeof(memory));//初始化备忘录
return dfs(n);
}
int dfs(int n)
{
if(memory[n] != -1)//看看备忘录中是否计算过当前结果
return memory[n];
if(n == 0 || n == 1)
{