Word Break
Can s be segmented into dictionary words? 1D DP over prefixes.
3 min read
dp string
Problem#
Can s be segmented into a space-separated sequence of words from wordDict?
Examples#
s = "leetcode", wordDict = ["leet","code"]→trues = "catsandog", wordDict = ["cats","dog","sand","and","cat"]→false
Constraints#
1 <= s.length <= 300.
Approach#
dp[i] = can s[0..i) be segmented. dp[0] = true. Transition: dp[i] = true iff some j < i has dp[j] && dict.contains(s[j..i)).
Solution#
class Solution {public: bool wordBreak(string s, vector<string>& wordDict) { unordered_set<string> dict(wordDict.begin(), wordDict.end()); int n = s.size(); vector<bool> dp(n + 1, false); dp[0] = true; for (int i = 1; i <= n; ++i) { for (int j = i - 1; j >= 0; --j) { if (dp[j] && dict.count(s.substr(j, i - j))) { dp[i] = true; break; } } } return dp[n]; }};func wordBreak(s string, wordDict []string) bool { dict := map[string]bool{} for _, w := range wordDict { dict[w] = true } n := len(s) dp := make([]bool, n+1) dp[0] = true for i := 1; i <= n; i++ { for j := i - 1; j >= 0; j-- { if dp[j] && dict[s[j:i]] { dp[i] = true break } } } return dp[n]}from typing import List
class Solution: def wordBreak(self, s: str, wordDict: List[str]) -> bool: dict_set = set(wordDict) n = len(s) dp = [False] * (n + 1) dp[0] = True for i in range(1, n + 1): for j in range(i - 1, -1, -1): if dp[j] and s[j:i] in dict_set: dp[i] = True break return dp[n]function wordBreak(s, wordDict) { const dict = new Set(wordDict); const n = s.length; const dp = new Array(n + 1).fill(false); dp[0] = true; for (let i = 1; i <= n; i++) { for (let j = i - 1; j >= 0; j--) { if (dp[j] && dict.has(s.slice(j, i))) { dp[i] = true; break; } } } return dp[n];}class Solution { public boolean wordBreak(String s, List<String> wordDict) { Set<String> dict = new HashSet<>(wordDict); int n = s.length(); boolean[] dp = new boolean[n + 1]; dp[0] = true; for (int i = 1; i <= n; i++) { for (int j = i - 1; j >= 0; j--) { if (dp[j] && dict.contains(s.substring(j, i))) { dp[i] = true; break; } } } return dp[n]; }}function wordBreak(s: string, wordDict: string[]): boolean { const dict = new Set<string>(wordDict); const n = s.length; const dp: boolean[] = new Array(n + 1).fill(false); dp[0] = true; for (let i = 1; i <= n; i++) { for (let j = i - 1; j >= 0; j--) { if (dp[j] && dict.has(s.slice(j, i))) { dp[i] = true; break; } } } return dp[n];}Editorial#
DP marks every reachable prefix. Once dp[i] flips true, we break early. Hashing each candidate substring costs O(L) per lookup; tighter implementations bound i - j by max word length.
Complexity#
- Time: O(n² * L).
- Space: O(n).
Concept revision#
Related#