140-word-break-ii

Try it on leetcode

Description

Given a string s and a dictionary of strings wordDict, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences in any order.

Note that the same word in the dictionary may be reused multiple times in the segmentation.

 

Example 1:

Input: s = "catsanddog", wordDict = ["cat","cats","and","sand","dog"]
Output: ["cats and dog","cat sand dog"]

Example 2:

Input: s = "pineapplepenapple", wordDict = ["apple","pen","applepen","pine","pineapple"]
Output: ["pine apple pen apple","pineapple pen apple","pine applepen apple"]
Explanation: Note that you are allowed to reuse a dictionary word.

Example 3:

Input: s = "catsandog", wordDict = ["cats","dog","sand","and","cat"]
Output: []

 

Constraints:

  • 1 <= s.length <= 20
  • 1 <= wordDict.length <= 1000
  • 1 <= wordDict[i].length <= 10
  • s and wordDict[i] consist of only lowercase English letters.
  • All the strings of wordDict are unique.

Solution(Python)

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> List[str]:
        return self.memo(s,wordDict)
        
    # Time Complexity: O(n*2^n)
    # Space Complexity: O(n*2^n)
    def bruteforce(self, s: str, wordDict: List[str]) -> List[str]:
        output, words = [], {}
        for word in wordDict:
            words[word] = True
       
        def backtrack(start:int, combo:list[str]) -> None:
            if start == len(s):
                output.append(" ".join(combo))
                return
            for i in range(start, len(s)):
                word = s[start:i+1]
                if word in words:
                    combo.append(word)
                    backtrack(i+1, combo)
                    combo.pop()
       
        backtrack(0, [])
        return output
    
    # Time Complexity: O(n*2)
    # Space Complexity: O(n*2)
    def memo(self, s: str, wordDict: List[str]) -> List[str]:
        wordDict = set(wordDict)
        memo = {}
        
        def search(string):
            if string in memo:
                return memo[string]
            else:
                paths = []
                
                # base case
                # we include this in here in the case a word
                # that exists in the dictionary can be further decomposed
                if string in wordDict:
                    paths.append(string)
                
                for i in range(len(string)):
                    # if a prefix exists, then see if remainder can be decomposed
                    if string[:i] in wordDict:
                        path = search(string[i:])
                        # if it can't be decomposed, then it will be empty
                        # for each decomposition, prepend the prefix
                        for p in path:
                            paths.append(string[:i] + " " + "".join(p))
                memo[string] = paths
                return memo[string]
        
        return search(s)