~25 minutes · Day 72 · dynamic programming
Tonight's interview shape is Word Break: given a string and a dictionary of words, decide whether the string can be split into valid dictionary chunks. The hard part is not checking one split. The hard part is avoiding the same suffix question over and over.
dp[i] answers “can the first i characters be segmented?” — true iff some earlier true dp[j] is followed by a dictionary word spanning j to i.
That sentence is the whole pattern. A true cell means a prefix is usable ground. From that ground, one dictionary word can carry you to a later true cell.
The brute force is to try every possible sequence of cuts: first word here, next word there, then recurse on the remaining suffix. That is exponential, O(2^n), because the same starting positions get retried through many different cut paths.
Dynamic programming keeps only the useful yes/no answer for each prefix. Use the four DP questions from the training plan:
dp[i] means the first i characters can be segmented.dp[j] is true and a dictionary word spans j to i, then dp[i] is true.dp[0] = True, because the empty prefix is already segmented.dp[len(s)].Python's set removes duplicate dictionary words, and str.startswith can test whether a word starts at a chosen index.
def wordBreak(s, wordDict):
words = set(wordDict) # unique dictionary words
n = len(s)
dp = [False] * (n + 1)
dp[0] = True # empty prefix works
for j in range(n + 1):
if not dp[j]:
continue # cannot extend a false prefix
for word in words:
i = j + len(word)
if i <= n and s.startswith(word, j):
dp[i] = True # word spans j -> i
return dp[n]
A product code is valid if it can be assembled from approved chunks. Given s = "applepenapple" and chunks ["apple", "pen"], predict the state, transition, base case, and answer location before opening the reveal.
Use the same prefix table. dp[0] starts true. From dp[0], the word "apple" spans to dp[5]. From dp[5], "pen" spans to dp[8]. From dp[8], "apple" spans to dp[13]. The answer is dp[13] = True.
| Approach | Time | Space |
|---|---|---|
| Brute force (try every cut path) | O(2^n) | O(n) |
| DP prefix table (extend true prefixes) | O(n * W * L) | O(n + W) |
Here n is the string length, W is the number of dictionary words, and L is the longest word length. The memory buys you a promise: each prefix question is stored once.
1. What does dp[i] mean?
dp[i] answers whether the first i characters can be segmented into dictionary words.2. When can dp[i] become true?
3. Spot the bug in this setup:
dp = [False] * (len(s) + 1)
for j in range(len(s) + 1):
if dp[j]:
# try words from j
dp[0] must start true. Without that base case, no dictionary word ever gets a reachable starting point.4. Which prompt is this pattern in disguise?
Solve this on LeetCode, logging it in your Notion tracker with the cycle — predict → attempt → compare → encode:
For the encode step, write four short sentences: state, transition, base case, answer location. That is the DP self-check gate for this lesson.
Watch NeetCode — Word Break after your attempt, as the compare step. Find the exact sentence where his reasoning diverges from yours.