https://leetcode.com/problems/word-break/
Word Break
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
For example, given
s = "leetcode"
,
dict = ["leet", "code"]
.
Return true because "leetcode"
can be segmented as "leet code"
.
DP Idea
You create a boolean array `f` of length `len(s)+1`. “`f[i] == True`” means substring `s[0:i-1]` can be matched successfully.
Jave code (Ref: https://leetcode.com/discuss/18904/java-implementation-using-dp-in-two-ways):
public class Solution { public boolean wordBreak(String s, Set<String> dict) { boolean[] f = new boolean[s.length() + 1]; Arrays.fill(f, false); f[0] = true; //Second DP for(int i=1; i <= s.length(); i++){ for(int j=0; j < i; j++){ if(f[j] && dict.contains(s.substring(j, i))){ f[i] = true; break; } } } return f[s.length()]; } }
This algorithm takes O(N^2) time complexity and O(N) space.
Python Code Using DP (Ref: https://leetcode.com/discuss/23605/simple-dp-solution-in-python-with-description)
def word_break(s, words): d = [False] * len(s) for i in range(len(s)): for w in words: if w == s[i-len(w)+1:i+1] and (d[i-len(w)] or i-len(w) == -1): d[i] = True return d[-1]
This algorithm improves the time complexity to O(NK) but still uses O(N) space.
Another improved Python Code
class Solution(object): def wordBreak(self, s, wordDict): """ :type s: str :type wordDict: Set[str] :rtype: bool """ break_idx = [] for i in xrange(len(s)): if s[0:i+1] in wordDict: break_idx.append(i) else: for b in break_idx: if s[b+1:i+1] in wordDict: break_idx.append(i) break return len(break_idx)>0 and break_idx[-1]== len(s)-1
This algorithm works better if you know there are only a few positions in `s` that can be segmented into words. (i.e., you know d[i]==True for only a small number of i, in the previous algorithm)
BFS Idea:
https://leetcode.com/discuss/8479/a-solution-using-bfs
But it is essentially similar to the DP idea. The time complexity is O(N^2).
Code
from collections import deque class Solution(object): def wordBreak(self, s, wordDict): """ :type s: str :type wordDict: Set[str] :rtype: bool """ l = deque([0]) visited = set() while l: n = l.popleft() for word in wordDict: start = n end = start + len(word) if s[start:end] == word and end not in visited: if end == len(s): return True l.append(end) visited.add(end) return False
You can also use Trie (prefix tree) to solve this problem. (TODO)