1. 程式人生 > >LeetCode 140. Word Break II(單詞切分)

LeetCode 140. Word Break II(單詞切分)

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];
    }
}