140.Word Break II

Tags: [backtracking], [DFS], [DP], [memo]

Com: {t}

Hard: [###]

Link: https://leetcode.com/problems/word-break-ii/\#/description

Given a non-empty string sand a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. You may assume the dictionary does not contain duplicate words.

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"].

UPDATE (2017/1/4):
The wordDict parameter had been changed to a list of strings (instead of a set of strings). Please reload the code definition to get the latest changes.


Solution: DSF, Backtracking, DP, Memo

public class Solution {
    public List<String> wordBreak(String s, List<String> wordDict) {
        if (s == null || s.length() == 0 || wordDict == null || wordDict.size() == 0) {
            return new ArrayList<>();
        }

        Set<String> dict = new HashSet<>(wordDict);
        Map<String, List<String>> memo = new HashMap<>();
        List<String> rest = wordBreakHelper(s, dict, memo);
        return rest != null ? rest : new ArrayList<>();
    }

    private List<String> wordBreakHelper(String s, Set<String> dict, Map<String, List<String>> memo) {
        if (memo.containsKey(s)) {
            return memo.get(s);
        }

        // base case.
        if (s.length() == 0) {
            return new ArrayList<>();
        }

        List<String> rest = new ArrayList<>();
        for (int i = 0; i < s.length(); i ++) {
            String w = s.substring(0, i + 1);
            if (!dict.contains(w)) {
                continue;
            }

            List<String> remainings = wordBreakHelper(s.substring(i + 1, s.length()), dict, memo);
            if (remainings == null) {
                // this means, if we use the current w, finally we cannot process the entire string.
                continue;
            }
            else if (remainings.size() == 0) {
                rest.add(w);
            } else {
                for (String remaining : remainings) {
                    rest.add(String.format("%s %s", w, remaining));
                }                
            }
        }

        if (rest.size() == 0) {
            memo.put(s, null);
            return null;
        }

        memo.put(s, rest);
        return rest;
    }
}

Revelation:

  • 第一个想法是DFS + Backtracking,往recursion function中出入 buff 和 rest,能得出正确答案,但是超时。所以我想到可以用DP memo, 但如果用DP memo就要重新定义recursion function的含义,让recursion可以返回值,那么新的recursion的含义就是:给定string s, dict, 返回能做出来的string list. (这种定义,就好像把recursion 变成stateless 的啦). 那么base case就是如果s 是空string那么没什么可以拼的,就返回empty list. Body of recursion:只需要看第一个word在哪里断开,如果这个word不在dict中,那么skip,如果这个word导致 remainings 是null,那么说明用当前cut的word会导致后面进行不完,所以也skip,如果remainings中有东西那么就迭代remainings中string逐个和当前的word进行拼接,如果remainings为空那么就直接把当前word放入rest中(rest中不会有重复), 最后在for loop结束后,如果rest还是空的,那么说明无法找到一个解,应该return null, 如果rest不为空就return rest, 应为在recursion的最开始已经查过base case了,所以如果这时rest还未空,那就说明当前情况无解.

Note:

  • Time complexity = O(n^2), n is the length of the given string, because there are n^2, substring for s, and the worst case, each substring will be memo's key, and each memo cell we only calculate once, so the worst case T = O(n^2).

Time Limited Exceeded: DFS, Backtracking

public class Solution {
    public List<String> wordBreak(String s, List<String> wordDict) {
        if (s == null || s.length() == 0 || wordDict == null || wordDict.size() == 0) {
            return new ArrayList<>();
        }

        List<String> buff = new ArrayList<>();
        List<String> rest = new ArrayList<>();
        Set<String> dict = new HashSet(wordDict);
        wordBreakHelper(s, dict, 0, buff, rest);
        return rest;
    }

    private void wordBreakHelper(String s, Set<String> dict, int index, List<String> buff, List<String> rest) {
        // base case
        if (index >= s.length()) {
            StringBuilder sbuilder = new StringBuilder();
            for (String w : buff) {
                sbuilder.append(w).append(' ');
            }
            if (sbuilder.length() > 0) {
                sbuilder.setLength(sbuilder.length() - 1);
            }
            rest.add(sbuilder.toString());
            return;
        }

        for (int i = index; i < s.length(); i ++) {
            String word = s.substring(index, i + 1);
            if (!dict.contains(word)) {
                continue;
            }

            buff.add(word);
            wordBreakHelper(s, dict, i + 1, buff, rest);
            buff.remove(buff.size() - 1);
        }
    }
}

Note:

  • Time complexity = O(n!), n is the length of the given string.

results matching ""

    No results matching ""