目录
1、记忆化搜索算法简介
1.1 什么是记忆化搜索
记忆化搜索(Memoization)是一种优化搜索算法的技术,主要用于减少重复计算,提高算法效率。它通过存储已经计算过的结果来避免对同一问题的重复计算,特别适用于递归算法中存在大量完全重复的递归的情况。
简单来说,记忆化搜索就是带备忘录的递归。
举个例子,当我们使用普通的暴搜递归法求斐波那契数时,意味着每个节点都需要遍历一遍,时间复杂度为O(2^N),但是这其中出现大量完全重复的递归树,大量重复的递归导致时间效率严重降低。这时,我们就可以使用一个“备忘录”所出现过的数据存起来,递归时若遇见重复的问题时,直接从“备忘录”中取值即可,不必再次重复递归。这样一来,我们可将时间复杂优化为线性级别:O(N)。
我们以添加“备忘录”的形式,将数据记忆起来,减少大量重复的递归,这样的暴搜优化( O(2^N) --> O(N) )算法就称为记忆化搜索。
注意:
并非所有的递归暴搜都可改为记忆化搜索,只有在递归的过程中,出现了大量完全相同的问题时(并非相同子问题),才可以使用记忆化搜索进行优化。
1.2 如何实现记忆化搜索
- 添加备忘录 ---> <可变参数,返回值>
- 每次进入递归的时候,瞅一瞅备忘录里面是否已存在想要的结果
- 每次递归返回的时候,将结果放到备忘录中存起来
1.3 记忆化搜索与动态规划的区别
其实记忆化搜索与动态规划本质上都是一回事。
- 都属于暴力解法(暴搜)
- 都是对暴搜的优化:把计算过的值,存起来
但是不同的是:
- 记忆化搜索是以递归的形式进行的
- 动态规划是以递推(循环)的形式进行的
- 记忆化搜索是自顶向下(dfs(n) --> dfs(n-1) 、 dfs(n-2))
- 动态规划是自底向上(dp[1] 、 dp[2] --> dp[3] )
2、算法应用【leetcode】
2.1 题一:斐波那契数
相信对于斐波那契数的计算,大家都已了然于心,这里就不多废话了,只向大家展示三中不同解法:
- 递归暴搜解法:O(2^N)
- 记忆化搜索解法(暴搜优化):O(N)
- 动态规划解法(暴搜优化):O(N)
2.1.1 递归暴搜解法代码
class Solution {
public int fib(int n) {
return dfs(n);
}
public int dfs(int n) {
if(n == 0 || n == 1) return n;
return dfs(n - 1) + dfs(n - 2);
}
}
2.1.2 记忆化搜索解法代码
class Solution {
//记忆化搜索
int[] memo;//memory
public int fib(int n) {
memo = new int[31];
Arrays.fill(memo, -1);//初始化时,填入不可能出现的值
return dfs(n);
}
public int dfs(int n) {
if(memo[n] != -1) return memo[n];
if(n == 0 || n == 1) {
memo[n] = n;
return n;
}
memo[n] = dfs(n - 1) + dfs(n - 2);