Word Break

MediumString DP · Prefix Reachability🧩 String DPLeetCode #139 ↗Updated

Problem

You are given a string s and a list of words wordDict. Decide whether s can be cut into one or more pieces so that every piece is a dictionary word. Words may be reused any number of times.
Input"leetcode", [leet,code]Outputtrue
Input"applepenapple", [apple,pen]Outputtrue
Input"catsandog", [cats,dog,sand,and,cat]Outputfalse

1 ≤ |s| ≤ 300  ·  1 ≤ |wordDict| ≤ 1000  ·  1 ≤ |word| ≤ 20  ·  lowercase letters, distinct words

Try it yourself

Java
class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
Whether the suffix starting at index i (or the prefix ending at i) can be segmented depends only on i — just n+1 distinct subproblems. Solve each once, and only try pieces no longer than the longest word.
PatternString DP

Instinct Two strings compared char by char (match, edit, interleave) means dp[i][j] over prefixes; one string's palindromes or splits means dp[l][r] or dp[i].

Memory hack Match? Go diagonal. Mismatch? Ask the neighbours. Up drops a char from s, left drops one from t, diagonal uses both.

Open the String DP guide →

Approaches

Brute ForcePlain Recursion over Cut Points

Time O(2n)Space O(n)

From index start, try every end: if s[start..end) is a word, recurse on the rest. A string like "aaa…ab" with words a, aa, aaa explores every one of the 2n-1 ways to cut it.

Java
public boolean wordBreak(String s, List<String> wordDict) {
    return canBreak(s, new HashSet<>(wordDict), 0);
}
private boolean canBreak(String s, Set<String> dict, int start) {
    if (start == s.length()) return true;
    for (int end = start + 1; end <= s.length(); end++) {
        if (dict.contains(s.substring(start, end)) && canBreak(s, dict, end)) return true;
    }
    return false;
}

Correct and tiny, but the same suffix is re-solved again and again.

At a glance

LevelApproachTimeSpace
Brute ForcePlain Recursion over Cut PointsO(2n)O(n)
BetterTop-Down MemoizationO(n3)O(n)
OptimalBottom-Up DP, Pieces ≤ Longest WordO(n·L2)O(n + m·L)
Common pitfalls
  • Greedy “take the longest matching word” fails: "abcd", [ab,abc,cd] needs the shorter ab.
  • Using List.contains — O(m) per lookup; convert to a HashSet first.
  • Forgetting dp[0] = true (empty prefix) — nothing ever becomes reachable.
Interview tips
  • Show the recursion first, then point at the repeated suffixes to justify memoization.
  • Mention the max-word-length bound — it turns O(n³) into ~O(n·L²).
  • Follow-up Word Break II asks for all sentences — output can be exponential.
Pattern
Prefix-reachability DP → “can the string be split into valid pieces?” (dp[i] from dp[j] + valid s[j..i)).
My notes saved in this browser