Given a string s
and a dictionary of strings wordDict
, return true
if s
can be segmented into a space-separated sequence of one or more dictionary words.
Note that the same word in the dictionary may be reused multiple times in the segmentation.
For example:
s = "leetcode", wordDict = ["leet","code"]
should return true
because "leetcode" can be segmented as "leet code".s = "applepenapple", wordDict = ["apple","pen"]
should return true
because "applepenapple" can be segmented as "apple pen apple". Note that you are allowed to reuse a dictionary word.s = "catsandog", wordDict = ["cats","dog","sand","and","cat"]
should return false
.How would you approach solving this problem? What would be the time and space complexity of your solution? Can you provide code?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to the word break problem is like trying all the possible ways to cut a long string into smaller pieces, and then checking if those pieces are valid words. It's like trying every combination until you find one that works. We explore every option, even if it takes a very long time.
Here's how the algorithm would work step-by-step:
def word_break(input_string, word_dictionary):
string_length = len(input_string)
def can_break(start_index):
# If we've reached the end, we've successfully broken the string
if start_index == string_length:
return True
for end_index in range(start_index + 1, string_length + 1):
# Check every substring starting from start_index
substring = input_string[start_index:end_index]
if substring in word_dictionary:
# If current substring is a valid word, explore the rest
if can_break(end_index):
return True
return False
# Initiate the recursion from the beginning of the string
return can_break(0)
The optimal solution uses a 'can we build this' strategy. It figures out if we can construct a sentence by breaking the given string into valid words from the provided dictionary, building up from small chunks.
Here's how the algorithm would work step-by-step:
def word_break(input_string, word_dictionary):
string_length = len(input_string)
reachable = [False] * (string_length + 1)
reachable[0] = True
# Mark the start of the string as reachable
for i in range(string_length):
if reachable[i]:
for word in word_dictionary:
if input_string[i:i + len(word)] == word:
# Mark the end of the valid word as reachable.
reachable[i + len(word)] = True
# Check if the entire string can be broken into words.
return reachable[string_length]
Case | How to Handle |
---|---|
Empty string s | Return true if wordDict is empty, otherwise return false as an empty string can only be segmented if the dictionary is empty. |
Empty wordDict | Return false as the string s cannot be segmented into words from an empty dictionary. |
s is a single character not present in wordDict | Return false because the single character cannot be segmented from the dictionary. |
s contains only one word which exists in wordDict | Return true as the entire string s can be segmented into this one word. |
s is very long and contains no valid segmentation | The dynamic programming approach should eventually determine that no valid segmentation exists and return false, but its performance needs to be considered. |
wordDict contains very long words that don't contribute to a solution | The algorithm should still work correctly, but performance might be impacted due to iterating over these long, useless words. |
wordDict contains duplicate words | The algorithm should work correctly as duplicates are redundant, though sets can improve efficiency by removing the duplicates. |
s can be segmented in multiple ways | The algorithm should return true as long as at least one valid segmentation is possible. |