LeetCode 140. Word Break II(單詞切分)
阿新 • • 發佈:2019-01-01
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"]
方法一:深度優先。
public class Solution { private ArrayList<String>[] scanned; private List<String> results = new ArrayList<>(); private void dfs(String s, int from, List<String> words, Set<String> wordDict) { if (from == s.length()) { String result = ""; for(int i=0; i<words.size(); i++) { if (i>0) result += " "; result += words.get(i); } results.add(result); return; } for(String word: scanned[from]) { words.add(word); dfs(s, from + word.length(), words, wordDict); words.remove(words.size()-1); } } public List<String> wordBreak(String s, Set<String> wordDict) { scanned = new ArrayList[s.length()]; scanned[0] = new ArrayList<>(); boolean reachable = false; for(int i=0; i<s.length(); i++) { if (scanned[i] == null) continue; for(String word: wordDict) { if (i + word.length() <= s.length() && word.equals(s.substring(i, i+word.length()))) { scanned[i].add(word); if (i+word.length() == s.length()) reachable = true; if (i+word.length() < s.length() && scanned[i+word.length()] == null) { scanned[i+word.length()] = new ArrayList<>(); } } } } if (!reachable) return results; dfs(s, 0, new ArrayList<>(), wordDict); return results; } }
優化以避免重複的判斷:
public class Solution { private void find(String s, List<Integer>[] substrings, int from, List<String> currents, List<String> results) { // System.out.printf("from=%d, currents=%s\n", from, currents); if (from == s.length()) { StringBuilder sb = new StringBuilder(); for(String current : currents) { if (sb.length() > 0) sb.append(" "); sb.append(current); } results.add(sb.toString()); return; } for(int length : substrings[from]) { currents.add(s.substring(from, from + length)); find(s, substrings, from + length, currents, results); currents.remove(currents.size() - 1); } } public List<String> wordBreak(String s, Set<String> wordDict) { Set<Integer> lengthSet = new HashSet<>(); for(String word : wordDict) { lengthSet.add(word.length()); } // System.out.printf("lengthSet=%s\n", lengthSet); int[] lengths = new int[lengthSet.size()]; int l = 0; for(int length : lengthSet) { lengths[l++] = length; } List<Integer>[] substrings = new List[s.length() + 1]; substrings[0] = new ArrayList<>(); for(int i = 0; i < s.length(); i++) { if (substrings[i] == null) continue; for(int j = 0; j < lengths.length; j++) { if (i + lengths[j] <= s.length() && wordDict.contains(s.substring(i, i + lengths[j]))) { substrings[i].add(lengths[j]); if (substrings[i + lengths[j]] == null) { substrings[i + lengths[j]] = new ArrayList<>(); } } } } // for(int i = 0; i < substrings.length; i++) { // System.out.printf("substrings[%d]=%s\n", i, substrings[i]); // } List<String> results = new ArrayList<>(); if (substrings[s.length()] == null) return results; find(s, substrings, 0, new ArrayList<>(), results); return results; } }
方法二:Trie+深度優先搜尋。
public class Solution {
private TrieNode root;
private void find(char[] sa, int from, int[] split, int splits, List<String> words) {
if (from == sa.length) {
char[] word = new char[sa.length+splits-1];
int wordPos = 0, splitPos = 0;
for(int i=0; i<sa.length; i++) {
if (i==split[splitPos]) { word[wordPos++] = ' '; splitPos++; }
word[wordPos++] = sa[i];
}
words.add(new String(word));
return;
}
TrieNode current = root;
for(int i=from;i<sa.length;i++) {
current = current.nexts[sa[i]-'a'];
if (current == null) break;
if (current.isWord) {
split[splits] = i+1;
find(sa, i+1, split, splits+1, words);
}
}
}
public List<String> wordBreak(String s, Set<String> wordDict) {
List<String> results = new ArrayList<>();
if (s==null || wordDict==null) return results;
root = new TrieNode();
for(String word: wordDict) {
char[] wa = word.toCharArray();
TrieNode current = root;
for(int i=0; i<wa.length; i++) current = current.add(wa[i]);
current.isWord = true;
}
char[] sa = s.toCharArray();
boolean[] reachable = new boolean[sa.length+1];
reachable[0] = true;
for(int i=0; i<sa.length; i++) {
if (!reachable[i]) continue;
TrieNode current = root;
for(int j=i;j<sa.length && current != null;j++) {
current = current.nexts[sa[j]-'a'];
if (current != null && current.isWord) reachable[j+1] = true;
}
}
if (!reachable[sa.length]) return results;
find(sa, 0, new int[sa.length], 0, results);
return results;
}
}
class TrieNode {
boolean isWord;
TrieNode[] nexts = new TrieNode[26];
TrieNode add(char ch) {
int i = ch - 'a';
if (nexts[i] != null) return nexts[i];
nexts[i] = new TrieNode();
return nexts[i];
}
}