赞
踩
- 在递归函数中, 在函数返回前,记录函数的返回结果。在下一次以同样参数访问函数时直接返回记录下的结果
- 也就是对递归树进行剪枝,遇到已经计算过的节点就不再继续往下计算,直接返回储存在hash table中的值
- 函数有返回值
- 函数返回结果和输入参数有关,和其他全局状态无关
- 参数列表中传入哈希表或者其他用于记录计算结果的数据结构
- 记忆化搜索是动态规划的一种实现方式, 也就是top-down approach
- 动态规划的另一种实现方式是多重循环 (找出动态转移方程,循环遍历), 也就是bottom-up approach
/* 利用dfs搜索 + 回溯 对于字符串 ss,如果某个前缀是单词列表中的单词,则拆分出该单词,然后对 s 的剩余部分继续拆分。如果可以将整个字符串 s 拆分成单词列表中的单词,则得到一个句子 Example: catsanddog c 不在字典里 ca 不在字典里 cat在字典里,所以将剩余部分 sanddog 送入递归, 进入下一层 以此类推 回溯时将每一层的字符串加入前一层返回的字符串 优化: 记忆化搜索 以上方法在个别测试用例时会超时,所以需要记忆化搜索剪枝 第一次查找后,用一个map记录每个index的答案 下次再遇到就直接用 */ class Solution { public List<String> wordBreak(String s, List<String> wordDict) { //用一个map实现记忆化搜索: <index, 这个index之后的所有答案> 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) { //查看目前的startIndex是否已经被查找过,如果是,则直接返回答案 if (memo.get(startIndex) != null) { return memo.get(startIndex); } //如果startIndex等于length,则说明已经触底,返回空 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++) { //如果startIndex到 i - 1 组成的字符串在字典里 (substring方法不包括最后的i,所以for loop是 i <= s.length()) if (wordDict.contains(s.substring(startIndex, i))) { //i为startIndex,进入下一次递归 List<String> tempList = dfs(s, wordDict, i, memo); //处理返回的答案,将startIndex到i组成的字符串加入到 返回的list中的每个字符串 for (String tempString: tempList) { //如果字符串为空,则后面不能有空格,特殊处理 if (tempString == "") { ans.add(s.substring(startIndex, i)); continue; } ans.add(s.substring(startIndex, i) + " " + tempString); } } //记录startIndex的所有答案 memo.put(startIndex, ans); } return ans; } }
/* 本题有两种解法: 第一种:记忆化递归 分别用ss和pp遍历字符串s和p case 1:如果 ss==pp 或者 pp= "?" 则ss++, pp++, 进入下一层递归 case 2:如果 pp == "*" for (int i = s_start; i <= s.length(); i++) { 将 i 和 pp + 1 送入递归函数, 进行对比 } 使用两个boolean数组:记录 visited[i][j] 和 results[i][j] 第二种:动态规范 */ 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) { //如果p_start等于p.length,则说明p字符串已经处理完毕,s需要也处理完毕,否则就是false //注意这里是p.length 不是 p.length - 1 if (p_start == p.length()) { return s_start == s.length(); } //如果s字符串处理完毕,则p剩下的字符需要全部是 * if (s_start == s.length()) { return ifAllStar(p, p_start); } //判断目前的index是否处理过 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 != '*') { //如果 ss==pp 或者 pp= "?" 则ss++, pp++, 进入下一层递归 match = ifSameChar(ss, pp) && helper(s, s_start + 1, p, p_start + 1, visited, results); } else { //这行代码和下面注释掉的fou loop是一个意思, 本质是 将 i不断递增 然后 和 pp + 1 送入递归函数, 进行对比 //注释掉的代码有点慢 match = helper(s, s_start, p, p_start + 1, visited, results) || helper(s, s_start + 1, p, p_start, visited, results); } /* else { for (int i = s_start; i <= s.length(); i++) { match = helper(s, i, p, p_start + 1, visited, results) || match; } } */ 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 == '?'); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。