Sale: Get 60% Off on all Pro Plans. Buy Now

Word Break

Problem

Given a string s and a list of strings wordDict, return true if s can be segmented into a space-separated sequence of one or more dictionary words from wordDict, and false otherwise.

  • 1 ≤ s.length ≤ 300
  • 1 ≤ wordDict.length ≤ 1000
  • 1 ≤ wordDict[i].length ≤ 20
  • s and wordDict[i] consist of only lowercase English letters
  • All the strings of wordDict are unique

Example

Input: s = "leetcode", wordDict = ["leet", "code"]
Output: true

The string "leetcode" can be segmented as "leet code". The algorithm starts at index 0 and tries prefixes: "l", "le", "lee", "leet". When it finds "leet" in the dictionary, it recursively checks the substring starting at index 4. From index 4, it finds "code" in the dictionary, and the recursion reaches the end of the string, returning true. This confirms the entire string can be segmented.

Approach

Straightforward Solution

A brute-force approach tries every possible prefix at each index and recursively checks the suffix, leading to exponential time complexity due to repeated computations of the same substrings.

Core Observation

The problem asks if the string can be segmented into dictionary words, which naturally breaks down into checking if prefixes are valid words and if the remaining suffix can also be segmented. This exhibits optimal substructure and overlapping subproblems, making it a prime candidate for dynamic programming.

Path to Optimal

Preview

Recognizing the overlapping subproblems, memoization caches results for each starting index to avoid redundant work. The problem is modeled as a top-down recursion with memoization, where dp(i) returns whether the substring s[i:] can be segmented…

Full step-by-step walkthrough on Pro

Optimal Approach

Preview

Use a recursive function dp(i) that returns true if s[i:] can be segmented. For each index i, iterate over possible end indices j, check if s[i:j+1] is in the dictionary, and recursively check dp(j+1)…

Full step-by-step walkthrough on Pro

Want the full reasoning chain?

Unlock the complete walkthrough, line-by-line analysis, and recall drill.

Unlock Pro

Time

O(n^3)

There are O(n) states (starting indices), and for each state, up to O(n) substrings are checked, with substring extraction and dictionary lookup costing O(n) in the worst case, resulting in O(n^3) time.

Space

O(n)

The memoization dictionary stores results for each index, requiring O(n) auxiliary space. The recursion stack depth is at most O(n). The input dictionary is not counted as auxiliary space.

Pattern Spotlight

Dynamic Programming (Top-Down Memoization)

When a problem involves checking all prefixes or suffixes with overlapping subproblems, use recursion with memoization to cache intermediate results and avoid exponential recomputation.

Solution

Python
1class Solution:
2 def wordBreak(self, s: str, wordDict: list[str]) -> bool:
3 memo = {}
4 word_set = set(wordDict)
5
6 def dp(i):
7 if i == len(s):
8 return True
9 if i in memo:
10 return memo[i]
11
12 for j in range(i, len(s)):
13 prefix = s[i : j + 1]
14 if prefix in word_set and dp(j + 1):
15 memo[i] = True
16 return True
17
18 memo[i] = False
19 return False
20
21 return dp(0)

Step-by-Step Solution

1

Initialize Memoization Cache and Dictionary Set

3memo = {}
4word_set = set(wordDict)

Objective

To prepare data structures for efficient lookup and caching of intermediate results.

Key Insight

Converting the word dictionary list into a set enables O(1) average-time membership checks, which is crucial for performance when checking prefixes. The memo dictionary caches results for each starting index, preventing repeated recursive calls on the same substring and drastically reducing time complexity.

Interview Quick-Check

Core Logic

Using a set for wordDict allows constant-time prefix membership checks, which is essential for efficient pruning.

Complexity

Memoization ensures each substring starting index is computed once, reducing the recursion tree size from exponential to linear in n.

2

Recursively Explore Prefixes and Memoize Results

To determine if the substring starting at index i can be segmented by exploring all prefixes and recursively checking suffixes.

3

Return Final Segmentation Result from Start of String

To initiate the recursive segmentation check from the beginning of the string and return the overall result.

2 more steps with full analysis available on Pro.

Line Analysis

This solution has 4 Critical lines interviewers watch for.

Line 14 Critical
if prefix in word_set and dp(j + 1):

Check if prefix is in the dictionary and recursively check suffix starting at j+1.

This line embodies the problem's optimal substructure by combining prefix validity and recursive suffix segmentation, forming the fundamental recursive decision that enables the DP solution.

Line 3 Critical
memo = {}

Initialize a memoization dictionary to cache results for substring start indices.

Memoization is essential to avoid redundant recursive calls on the same substring, reducing exponential complexity to polynomial time.

Line 7 Critical
if i == len(s):

Return true if the starting index reaches the end of the string.

Reaching the end means the entire string has been successfully segmented, serving as the base case for recursion.

Full line-by-line criticality + rationale for all 14 lines available on Pro.

Test Your Understanding

Why is memoization critical in this recursive solution for Word Break?

See the answer with Pro.

Related Problems

Dynamic Programming pattern

Don't just read it. Drill it.

Reconstruct Word Break from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the Word Break drill

or drill a free problem