lintcode582 - Word Break II - hard
Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word.
Return all such possible sentences.
Example
Gieve s = lintcode,
dict = ["de", "ding", "co", "code", "lint"].
A solution is ["lint code", "lint co de"].
1.DFS,带记忆化搜索。
这题很容易TLE或MLE,尤其是当你试着扫描每段头尾不同的substring在不在字典里的时候会有很多重复功。减少时间复杂度的方法可以用记忆化搜索,比如1-5的分割我记下来了,以后6-10正好和1-5长一样,那我就不重新算,而是直接拿存过的分割结果了。实现这个功能的容器就是Map<String, List<String>>。
DFS函数头:private List<String> breakHelper(String s, Set<String> wordDict, Map<String, List<String>> memo)
目标:找出所有把s大卸八块的方式,拷贝一份放到memo里,再把这份方式返回。
流程:memo有了就直接拿了走人;遍历所有把s一分两半的方式,如果前半段字典里有,就DFS要一下所有后半段大卸八块的方式;把前半段和所有后半段的方式拼起来就是当前的结果了;存结果;返回结果。
细节:整个s就在字典里的情况要分出来处理,因为你没办法分s为s(0, length)和substring(length, length), 后面那样是编译错误的。
2.普通DFS
就是比较类似subset那些题目的做法,传index做,sb就像crt一样。但是会MLE哦,因为字典最长的可能也就5个字符,你一直拿30-1000的字符串去看在不在字典里,其实有很多无用功。前面那种做法其实也有这样做,但是它还是靠记忆化帮忙减少很多了,比如mmmmmmm…mmmmm走过一次流程发现没有分段方法,也会存个空集结果放到map里,下次再遇到一样的长字符串就不会再算了,直接返回空集上上级没办法粘出有效字符串。
细节:StringBuilder.delete(from, to)方法,里面填的参数和substring一样,头包括,尾包括,两者相减是长度。
1.DFS,带记忆化
public class Solution { /* * @param s: A string * @param wordDict: A set of words. * @return: All possible sentences. */ public List<String> wordBreak(String s, Set<String> wordDict) { // write your code here List<String> result = new ArrayList<>(); if (s == null || wordDict == null) { return result; } result = breakHelper(s, wordDict, new HashMap<String, List<String>>()); return result; } private List<String> breakHelper(String s, Set<String> wordDict, Map<String, List<String>> memo) { if (memo.containsKey(s)) { return memo.get(s); } List<String> result = new ArrayList<>(); for (int i = 1; i < s.length(); i++) { String substring = s.substring(0, i); if (!wordDict.contains(substring)) { continue; } List<String> suffixResult = breakHelper(s.substring(i), wordDict, memo); for (String item : suffixResult) { result.add(substring + " " + item); } } if (wordDict.contains(s)) { result.add(s); } memo.put(s, result); return result; } }
2. 普通DFS,(正确但TLE)
public class Solution { /* * @param s: A string * @param wordDict: A set of words. * @return: All possible sentences. */ public List<String> wordBreak(String s, Set<String> wordDict) { // write your code here List<String> result = new ArrayList<>(); if (s == null || wordDict == null || (s.length() == 0 && !wordDict.contains(""))) { return result; } breakHelper(s, wordDict, 0, new StringBuilder(), result); return result; } private void breakHelper(String s, Set<String> wordDict, int index, StringBuilder sb, List<String> result) { if (index == s.length()) { result.add(sb.toString()); return; } for (int i = index + 1; i <= s.length(); i++) { String substring = s.substring(index, i); if (!wordDict.contains(substring)) { continue; } if (index > 0) { sb.append(" "); } sb.append(substring); breakHelper(s, wordDict, i, sb, result); // 注意这个方法, 而且不可以sb.delete(index, i);,前面加了空格不一样了 sb.delete(sb.length() - (i - index), sb.length()); if (index > 0) { sb.delete(sb.length() - 1, sb.length()); } } } }