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.
For example, given
s = "catsanddog"
,
dict = ["cat", "cats", "and", "sand", "dog"]
.
A solution is ["cats and dog", "cat sand dog"]
.
方法一:Runtime: 15 ms beats 47.49% of javasubmissions.
public List<String> wordBreak3(String s, Set<String> wordDict) {
Map<String, ArrayList<String>> map = new HashMap<>();
return wordBreakHelper(s, wordDict, map);
}
public List<String> wordBreakHelper(String s, Set<String> dict, Map<String, ArrayList<String>> memo) {
if (memo.containsKey(s)) return memo.get(s);
ArrayList<String> result = new ArrayList<>();
int n = s.length();
if (n <= 0) return result;
for (int len = 1; len <= n; ++len) {
String prefix = s.substring(0, len);
if (dict.contains(prefix)) {
if (len == n) {
result.add(prefix);
} else {
String suffix = s.substring(len);
List<String> tmp = wordBreakHelper(suffix, dict, memo);
for (String item : tmp) {
item = prefix + " " + item;
result.add(item);
}
}
}
}
memo.put(s, result);
return result;
}
参考:http://www.jiuzhang.com/solutions/word-break-ii/
方法二:
Runtime: 6 ms beats 94.01% of javasubmissions.
思路:判断s.substring(0,i)如果是字典里的word,如果是,递归判断s.substring(i)的字符串分解情况。
具体过程如下:
1.判断s.substring(0,i)如果是字典里的word,那么就继续判断后截儿字符串s.substring( i )的情况;
2.判断后截儿字符串s.substring( i )是否可分解,以及s.substring( i )分解的字符串集合,如果s.substring(i,i+x)是字典里的word,那么就判断s.substring(x)是否可分解,以及获取从x位之后s.substring( x )分解的字符串集合;
3.重复2步骤,判断s.substring( x )是否可分解,以及s.substring( x)分解的字符串集合。在分解的过程中,我们会获取到invalid[x]的值,因此可知s.substring( x )是否可分解。当第1步骤中递归中的for循环到s.substring(0,x)的时候,如果invalid[x]已经是true,可确定x之后的字符串是不可分的,那就直接跳过继续往后判断了;
最初的时候,我们是设定invalid[x]为false的,即我们是不确定invalid[x]的值(invalid[x]初始化也为false),因此不知道后截儿字符串是否可分,所以我们继续往下判断。
public List<String> wordBreak4(String s, Set<String> wordDict) {
List<String> res = new ArrayList<>();
wordBreak(s, 0, wordDict, "", new boolean[s.length() + 1], res);
return res;
}
/**
* Helper function for Leetcode 140. Word Break II.
*
* @param s string to break
* @param left start point
* @param wordDict dictionary
* @param prev previous word found
* @param invalid invalid[i] means whether [i, s.length()) is unbreakable
* @param res list to store results
* @return true if s.substring(left) is breakable.
*/
private boolean wordBreak(String s, int left, Set<String> wordDict, String prev, boolean[] invalid, List<String> res) {
if (left == s.length()) {// Base case: successfully moved to the end, add result to the list.
res.add(prev.trim());//去掉prev首尾的空格
return true;
}
boolean possible = false;// whether s.substring(left) is breakable
for (int i = left + 1; i <= s.length(); i++) {// find whether [left, i) is valid
if (invalid[i]) continue;// if s.substring(i) is unbreakable, continue
String sub = s.substring(left, i);
if (wordDict.contains(sub)) {
boolean flag = wordBreak(s, i, wordDict, prev.concat(" ").concat(sub), invalid, res);
possible = flag || possible;// as long as at least one valid substring [i, end), possible is true
}
}
invalid[left] = !possible;// update invalid array
return possible;
}