https://leetcode.com/problems/word-break-ii/
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"]
.
Code
class Solution(object): # For reference, this is Word Break I problem: https://czxttkl.com/?p=930 def wordBreak1(self, s, words): d = [False] * len(s) for i in range(len(s)): for w in words: if w == s[i-len(w)+1:i+1] and (d[i-len(w)] or i-len(w) == -1): d[i] = True return d[-1] def wordBreak(self, s, wordDict): """ :type s: str :type wordDict: Set[str] :rtype: List[str] """ # To pass a test case, I need to first check a word is breakable or not. # We don't need this actually. if not self.wordBreak1(s, wordDict): return [] self.res = [] self.words = set(wordDict) self.helper(s, "") return self.res def helper(self, s, concat): for i in xrange(1, len(s)+1): if s[0:i] in self.words: concat_cp = concat + ' ' + s[0:i] if i == len(s): # strip to remove first ' ' self.res += [concat_cp[1:]] else: self.helper(s[i:], concat_cp)
Idea:
DFS essentially. The time complexity is O(3^N), where N is the length of s. How to get this time complexity?
T(1)=T(1) T(2)=(T(1)+T(1))+T(1) = 3T(1) # Check if the first character and the second character are words in the dictionary, or check # if the whole two characters form a word in the dictionary T(3) = (T(1)+T(2))+(T(2)+T(1))+T(1) # Check if the first character and the last two characters are words in the dictionary, or # check if the first two characters and the last character are words in the dictionary, or # check if the whole three characters form a word in the dictionary. ... T(N) = (T(1)+T(N-1))+(T(2)+T(N-2))+...+(T(N-1)+T(1))+T(1) = 3T(N-1)
Since the time complexity is exponential, leetcode doesn’t pass my code for certain test cases. I added the function from Word Break I to first check if a word is breakable. If yes, then I continue to generate return strings. In this way I passed the leetcode OJ.
To alleviate the duplication of computation, we can use dynamic programming idea to have more space in trade of the time. But I don’t think it can alleviate the time complexity of the worst case.
Code (https://leetcode.com/discuss/64513/python-dp-solution-in-11-lines):
def wordBreak(self, s, wordDict): """ :type s: str :type wordDict: Set[str] :rtype: List[str] """ M = {} def dfs(remain_str): if not remain_str: return [''] if remain_str in M: return M[remain_str] ret = [] for i in xrange(1,len(remain_str)+1): if remain_str[:i] in wordDict: for r in dfs(remain_str[i:]): ret.append( (remain_str[:i]+' '+r).strip() ) M[remain_str] = tuple(ret) return ret return dfs(s)