- Interview Questions
- /
- Problems
- /
- Word Break II
Word Break II
Return every way to split a string into dictionary words, as space-separated sentences. Tests backtracking with memoization, and knowing when the output itself is the cost. Solve it below in Python or JavaScript, then read the walkthrough.
Problem
You're given a string s and a list of dictionary words wordDict. Insert spaces into s so that every piece is a word from the dictionary, and return every sentence you can make this way.
A dictionary word may be used any number of times. Each sentence is the pieces joined by single spaces, with no leading or trailing space. If s cannot be split at all, return an empty list.
Return the sentences in any order.
Example 1
- Input
- s = "icecreamcone", wordDict = ["ice", "cream", "icecream", "cone", "creamcone", "am"]
- Output
- ["ice cream cone", "ice creamcone", "icecream cone"]
"am" is in the dictionary, but no split that uses it covers the rest of the string.
Example 2
- Input
- s = "aaaa", wordDict = ["a", "aa"]
- Output
- ["a a a a", "a a aa", "a aa a", "aa a a", "aa aa"]
Words can be reused, so every way to cut the string into 1s and 2s counts.
Example 3
- Input
- s = "dogcatbird", wordDict = ["dog", "cat", "fish"]
- Output
- []
"bird" is not in the dictionary, so no split works.
Constraints
- 1 ≤ s.length ≤ 25
- 1 ≤ wordDict.length ≤ 1000, and 1 ≤ wordDict[i].length ≤ 10
- s and every word contain only lowercase English letters.
- All words in wordDict are distinct.
- The total number of sentences is at most 10⁵.
Practice
Runs 12 tests in your browser. Python loads on the first run (about 6 MB, then cached). Press ⌘/Ctrl + Enter to run.
Get asked Word Break II in a real interview?
Interview Solver gives you a working solution live, during your actual coding interview. Invisible to screensharing.
How to solve Word Break II
Pattern: Backtracking with memoization
Every sentence starts with some dictionary word that is a prefix of s. Once you pick that first word, what remains is the same problem on a shorter suffix. So the natural shape is recursive: "all sentences for s[i:]" = for each word that starts at i, that word followed by each sentence for the rest.
The catch is repeated work. Different first choices often land on the same suffix ("a" + "a" and "aa" both reach index 2), and plain backtracking re-solves that suffix every time. Worse, a string like "aaaa...ab" has millions of partial splits that all die at the final b.
Caching the list of sentences for each start index fixes both: each suffix is solved once, and a suffix with no solutions is remembered as empty, so dead ends are pruned immediately.
Approach 1: Plain backtracking
From index i, try every word that matches at i, recurse on the rest, and record the sentence when you reach the end. Easy to write, but it explores every partial split, which is exponential on inputs like "aaaa...ab" even when the answer is empty.
Time O(2ⁿ · n) · Space O(n) recursion plus output
Approach 2: Word Break DP check, then backtrack
First compute ok[i], whether s[i:] can be split at all, with the classic O(n²) DP. Then backtrack, but only step to indices where ok is true. Dead ends are skipped, though shared suffixes are still rebuilt each time they are reached.
Time O(n² + output) · Space O(n) plus output
Approach 3: Memoized suffix sentences
Define solve(i) as the list of sentences for s[i:], with solve(n) = [""].
- For each end
jfromi + 1ton, ifs[i:j]is a word, combine it with every sentence insolve(j). - Cache the result for
i.
Each index is solved once. The remaining cost is building the sentences, which is unavoidable because they are the output.
Time O(n² + total output size) · Space O(total output size)
| Approach | Time | Space |
|---|---|---|
| Plain backtracking | O(2ⁿ · n) | O(n) recursion plus output |
| Word Break DP check, then backtrack | O(n² + output) | O(n) plus output |
| Memoized suffix sentences | O(n² + total output size) | O(total output size) |
Solution code
Try the practice editor first. Both solutions pass every test above.
Word Break II solution in Python
def word_break(s: str, word_dict: list[str]) -> list[str]:
words = set(word_dict)
longest = max(map(len, words))
memo: dict[int, list[str]] = {len(s): [""]}
def solve(i: int) -> list[str]:
if i in memo:
return memo[i]
sentences = []
for j in range(i + 1, min(len(s), i + longest) + 1):
word = s[i:j]
if word in words:
for rest in solve(j):
sentences.append(word + " " + rest if rest else word)
memo[i] = sentences
return sentences
return solve(0)Word Break II solution in JavaScript
function wordBreak(s, wordDict) {
const words = new Set(wordDict);
const longest = Math.max(...wordDict.map((w) => w.length));
const memo = new Map([[s.length, ['']]]);
function solve(i) {
if (memo.has(i)) return memo.get(i);
const sentences = [];
for (let j = i + 1; j <= Math.min(s.length, i + longest); j++) {
const word = s.slice(i, j);
if (!words.has(word)) continue;
for (const rest of solve(j)) {
sentences.push(rest ? word + ' ' + rest : word);
}
}
memo.set(i, sentences);
return sentences;
}
return solve(0);
}Common mistakes
- Searching the dictionary as a list for every substring. Put it in a set first.
- Adding a trailing or leading space when combining a word with the empty sentence at the end of the string.
- Not caching empty results, so failing suffixes are re-explored. This is what makes `"aaaa...ab"` time out.
- Returning a single sentence, or a boolean, instead of every possible sentence.
- Claiming a polynomial bound. The output can be exponential in n, so no algorithm beats its size.
What interviewers look for
Start from Word Break I if you know it: "the boolean version is a DP over suffixes; this version keeps the actual sentences instead of true/false." That framing shows you see the connection.
Be honest about complexity. Interviewers listen for you saying that the number of sentences can be exponential, so the goal is to avoid wasted work, not to make the output smaller. Then call out the input that breaks plain backtracking, a long run of as ending in a letter that is not in the dictionary, and explain how memoizing empty results handles it.
Follow-up questions
How would you only count the number of sentences?
Store a count per index instead of a list: count[n] = 1, and count[i] is the sum of count[j] over every word s[i:j]. That is O(n²) time with O(n) space, no matter how many sentences there are.
How would you speed up the inner loop with a large dictionary?
Only try lengths up to the longest word, or build a trie of the words and walk it from index i, stopping as soon as no word continues. Each step from i then costs at most the length of the longest word.
What if you wanted the split with the fewest words?
That is a shortest-path problem over indices: each word from i to j is an edge. A BFS from index 0, or a DP storing the fewest words per suffix, finds it in O(n²) without generating every sentence.
Companies that ask Word Break II
Word Break II is tagged by 98 companies in our interview dataset. The score shows how often it comes up at each company.
- And Digital100%
- Ericsson100%
- Shield AI100%
- Quantiphi100%
- Tokopedia100%
- Twitter93.7%
- Dropbox92.1%
- Coforge92%
- Mozilla91%
- Irobot90%
- Moveworks89.8%
- Segment89%
- Iodine Software87%
- Opendoor87%
- Snap85.2%
- Vinted82%
- Glovo82%
- Storyblocks82%
- Carbon Health82%
- Roche81%
- Boston Scientific79%
- Kajabi79%
- 10x Genomics78%
- Digitalocean77%
and 74 more.
Practice next
Get live help in the real interview
Working solutions in real time during your actual interview. Invisible to screensharing.
Start Free TrialNo credit card required