139. Word Break
mediumAsked at GustoDetermine if a string can be segmented into words from a dictionary. Gusto asks this to test DP thinking — specifically whether you can define the right subproblem and build the table bottom-up without getting tangled in overlapping recursion.
By Alex Chen, Founder, InterviewChamp.AI · Last verified
Source citations
Public interview reports confirming this problem appears in Gusto loops.
- Glassdoor (2025-10)— Reported in Gusto mid-level SWE onsite reports as a DP medium used to test string decomposition thinking.
- Blind (2025-08)— Gusto threads list Word Break as a go-to DP string problem in engineering interviews.
Problem
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. The same word in the dictionary may be reused multiple times.
Constraints
1 <= s.length <= 3001 <= wordDict.length <= 10001 <= wordDict[i].length <= 20s and wordDict[i] consist of only lowercase English letters.All the strings in wordDict are unique.
Examples
Example 1
s = "leetcode", wordDict = ["leet","code"]trueExplanation: 'leetcode' = 'leet' + 'code'.
Example 2
s = "applepenapple", wordDict = ["apple","pen"]trueExplanation: 'applepenapple' = 'apple' + 'pen' + 'apple'. Dictionary words may be reused.
Example 3
s = "catsandog", wordDict = ["cats","dog","sand","and","cat"]falseExplanation: No valid segmentation exists.
Approaches
1. Bottom-up DP
dp[i] = true if s[0..i-1] can be segmented. For each position i, check all j < i: if dp[j] is true and s[j..i-1] is in the wordSet, then dp[i] = true.
- Time
- O(n³) with string slicing, O(n² · m) with trie
- Space
- O(n + wordSet size)
function wordBreak(s, wordDict) {
const wordSet = new Set(wordDict);
const n = s.length;
const dp = new Array(n + 1).fill(false);
dp[0] = true; // empty prefix is always segmentable
for (let i = 1; i <= n; i++) {
for (let j = 0; j < i; j++) {
if (dp[j] && wordSet.has(s.slice(j, i))) {
dp[i] = true;
break; // no need to check further j values
}
}
}
return dp[n];
}Tradeoff: O(n²) outer loops × O(n) for string slicing = O(n³). For n ≤ 300 this is fast enough. Using a Set for O(1) word lookup is important — list lookup would add another factor.
2. Memoised recursion (top-down DP)
Recursively try all dictionary words as the next segment. Memoise by start index to avoid recomputation.
- Time
- O(n² · m) where m is max word length
- Space
- O(n)
function wordBreak(s, wordDict) {
const wordSet = new Set(wordDict);
const memo = new Map();
function canBreak(start) {
if (start === s.length) return true;
if (memo.has(start)) return memo.get(start);
for (let end = start + 1; end <= s.length; end++) {
if (wordSet.has(s.slice(start, end)) && canBreak(end)) {
memo.set(start, true);
return true;
}
}
memo.set(start, false);
return false;
}
return canBreak(0);
}Tradeoff: Equivalent complexity to the bottom-up approach but uses the call stack. Good for candidates more comfortable with recursion. The memo prevents recomputing the same suffix multiple times.
Gusto-specific tips
Define the subproblem before coding: 'dp[i] = can the first i characters of s be segmented?' Gusto interviewers look for the base case explanation — dp[0] = true because an empty string requires no words. The break statement after finding a valid j is a nice optimisation to mention. Also consider converting wordDict to a Set before the DP loop — not after.
Common mistakes
- Initialising dp[0] to false — the empty prefix is always valid; dp[0] = true is the required base case.
- Using wordDict.includes() instead of a Set — O(m) lookup per check, turning the overall complexity to O(n² × m²).
- Off-by-one: s.slice(j, i) covers indices j through i-1 — verify this matches the dp[j] and dp[i] semantics.
- In the recursive version, not memoising — leads to exponential time on pathological inputs.
Follow-up questions
An interviewer at Gusto may pivot to one of these next:
- Word Break II (LC 140) — return all possible segmentations as strings.
- What if some words in the dictionary overlap (one is a prefix of another)?
- How would you optimise using a Trie to avoid the string slicing cost?
Solve it now
Free. No sign-up. Python and JavaScript run instantly in your browser.
FAQ
Why is dp[0] = true?
It represents the empty prefix, which is trivially segmentable (using zero words). Without this base case, dp[word.length] would never become true for any first word.
Does reusing words from the dictionary cause issues?
No — the DP naturally handles reuse since the same word can match at multiple (j, i) pairs.
What is the worst-case input?
A string like 'aaa...a' with words like 'a', 'aa', 'aaa' maximises the number of valid segmentations — but the DP still runs in O(n²) since we memoize/tabulate.
Practice these live with InterviewChamp.AI
Drill Word Break and other Gusto interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.
Practice these live with InterviewChamp.AI →