记忆化搜索 Memorization Search
什么是记忆化搜索
- 在递归函数中, 在函数返回前,记录函数的返回结果。在下一次以同样参数访问函数时直接返回记录下的结果
- 也就是对递归树进行剪枝,遇到已经计算过的节点就不再继续往下计算,直接返回储存在hash table中的值
记忆化搜索函数的三个特点
- 函数有返回值
- 函数返回结果和输入参数有关,和其他全局状态无关
- 参数列表中传入哈希表或者其他用于记录计算结果的数据结构
记忆化搜索 vs 动态规划
- 记忆化搜索是动态规划的一种实现方式, 也就是top-down approach
- 动态规划的另一种实现方式是多重循环 (找出动态转移方程,循环遍历), 也就是bottom-up approach
三种适用于DP的场景
三种不适用于DP的场景
Examples:
Leetcode 140: 单词拆分 II
class Solution {
public List<String> wordBreak(String s, List<String> wordDict) {
Map<Integer, List<String>> memo = new HashMap<>();
return dfs(s, wordDict, 0, memo);
}
public List<String> dfs(String s, List<String> wordDict, int startIndex, Map<Integer, List<String>> memo) {
if (memo.get(startIndex) != null) {
return memo.get(startIndex);
}
if (startIndex == s.length()) {
List<String> list = new ArrayList<>();
list.add("");
return list;
}
List<String> ans = new ArrayList<>();
for (int i = startIndex; i <= s.length(); i++) {
if (wordDict.contains(s.substring(startIndex, i))) {
List<String> tempList = dfs(s, wordDict, i, memo);
for (String tempString: tempList) {
if (tempString == "") {
ans.add(s.substring(startIndex, i));
continue;
}
ans.add(s.substring(startIndex, i) + " " + tempString);
}
}
memo.put(startIndex, ans);
}
return ans;
}
}
Leetcode 44: 通配符匹配
class Solution {
public boolean isMatch(String s, String p) {
if (s ==null || p == null) {
return false;
}
boolean [][] visited = new boolean[s.length()][p.length()];
boolean [][] results = new boolean[s.length()][p.length()];
return helper(s, 0, p, 0, visited, results);
}
public boolean helper(String s, int s_start, String p, int p_start,
boolean [][] visited, boolean [][] results) {
if (p_start == p.length()) {
return s_start == s.length();
}
if (s_start == s.length()) {
return ifAllStar(p, p_start);
}
if (visited[s_start][p_start]) {
return results[s_start][p_start];
}
char pp = p.charAt(p_start);
char ss = s.charAt(s_start);
boolean match = false;
if (pp != '*') {
match = ifSameChar(ss, pp) && helper(s, s_start + 1, p, p_start + 1, visited, results);
}
else {
match = helper(s, s_start, p, p_start + 1, visited, results) || helper(s, s_start + 1, p, p_start, visited, results);
}
results[s_start][p_start] = match;
visited[s_start][p_start] = true;
return match;
}
private boolean ifAllStar(String p, int p_start) {
for(int i = p_start; i < p.length(); i++) {
if (p.charAt(i) != '*') {
return false;
}
}
return true;
}
private boolean ifSameChar(char s, char p) {
return (s == p || p == '?');
}
}