Home
DSA Patterns
Dynamic Programming
Word Break
Word Break
Decide whether the string s can be cut, end to end, into pieces that each appear in a given list of dictionary words, where any word may be used more than once.
Examples
The cut at 4 reaches "leet", and "code" finishes it.
Dictionary words may be reused, so "apple" is used twice.
Both "cats" and "cat" start it, but neither leaves a remainder the dictionary can finish.
Problem Understanding
We need to check if the entire string can be built using dictionary words. Words can be reused.
Example: s = "leetcode", dict = ["leet", "code"]
- "leet" + "code" -> Valid
- Output:
true
Algorithm Strategy
Let dp[i] be true when the first i characters can be cut into dictionary words.
Recurrence: dp[i] is true if there is some j < i where
dp[j]is true — the firstjcharacters already segment, ands[j...i)is in the dictionary.
Base case: dp[0] = true. The empty prefix needs no words, and it is what the first real word stands on.
One working j settles the question, so the inner loop stops at the first one it finds.
Interactive Visualization
Column i is the verdict on the first i characters. When a cut point is tested, its cell and the letters of the piece between it and i light together — so dp[j] and s[j:i] in words can be read straight off the picture.
Try Example 3: "cats" and "cat" both start it, and neither leaves a remainder the dictionary can finish.
Dry Run
s = "applepen", dict = ["apple", "pen"]
| i | Substr tested | Valid split at j? | dp[i] Result |
|---|---|---|---|
| 0 | "" | - | T (Base) |
| ... | ... | ... | ... |
| 5 | "apple" | j=0 (dp[0]=T) & "apple" in dict |
T |
| ... | ... | ... | ... |
| 8 | "pen" (from 5) | j=5 (dp[5]=T) & "pen" in dict |
T |
Edge Cases & Common Mistakes
Common pitfalls:
Words may be reused. "applepenapple" needs "apple" twice, and nothing in the recurrence forbids it — dp never tracks which words were spent.
dp[0] = true is what starts it. Without it no first word can ever be accepted, because every cut of a prefix has to stand on an earlier true cell.
An early word is not a commitment. "catsandog" reaches "cats" and gets stuck, and reaching "cat" does not help either. Only a false at dp[n] settles it.
Solution
Every cut point tried, stopping at the first that works — the lines light up as the figure above steps.
Word Break Code
1var wordBreak = function(s, wordDict) {2 const n = s.length;3 const words = new Set(wordDict);4 const dp = new Array(n + 1).fill(false);5 dp[0] = true;6 for (let i = 1; i <= n; i++) {7 for (let j = 0; j < i; j++) {8 if (dp[j] && words.has(s.slice(j, i))) {9 dp[i] = true;10 break;11 }12 }13 }14 return dp[n];15};
