LeetCode – Word Break II (Java)
Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences. For example, given s = "catsanddog", dict = ["cat", "cats", "and", "sand", "dog"], the solution is ["cats and dog", "cat sand dog"].
Java Solution 1 - Dynamic Programming
This problem is very similar to Word Break. Instead of using a boolean array to track the matched positions, we need to track the actual matched words. Then we can use depth first search to get all the possible paths, i.e., the list of strings.
The following diagram shows the structure of the tracking array.
public static List<String> wordBreak(String s, Set<String> dict) { //create an array of ArrayList<String> List<String> dp[] = new ArrayList[s.length()+1]; dp[0] = new ArrayList<String>(); for(int i=0; i<s.length(); i++){ if( dp[i] == null ) continue; for(String word:dict){ int len = word.length(); int end = i+len; if(end > s.length()) continue; if(s.substring(i,end).equals(word)){ if(dp[end] == null){ dp[end] = new ArrayList<String>(); } dp[end].add(word); } } } List<String> result = new LinkedList<String>(); if(dp[s.length()] == null) return result; ArrayList<String> temp = new ArrayList<String>(); dfs(dp, s.length(), result, temp); return result; } public static void dfs(List<String> dp[],int end,List<String> result, ArrayList<String> tmp){ if(end <= 0){ String path = tmp.get(tmp.size()-1); for(int i=tmp.size()-2; i>=0; i--){ path += " " + tmp.get(i) ; } result.add(path); return; } for(String str : dp[end]){ tmp.add(str); dfs(dp, end-str.length(), result, tmp); tmp.remove(tmp.size()-1); } } |
Java Solution 2 - Simplified
public List<String> wordBreak(String s, Set<String> wordDict) { ArrayList<String> [] pos = new ArrayList[s.length()+1]; pos[0]=new ArrayList<String>(); for(int i=0; i<s.length(); i++){ if(pos[i]!=null){ for(int j=i+1; j<=s.length(); j++){ String sub = s.substring(i,j); if(wordDict.contains(sub)){ if(pos[j]==null){ ArrayList<String> list = new ArrayList<String>(); list.add(sub); pos[j]=list; }else{ pos[j].add(sub); } } } } } if(pos[s.length()]==null){ return new ArrayList<String>(); }else{ ArrayList<String> result = new ArrayList<String>(); dfs(pos, result, "", s.length()); return result; } } public void dfs(ArrayList<String> [] pos, ArrayList<String> result, String curr, int i){ if(i==0){ result.add(curr.trim()); return; } for(String s: pos[i]){ String combined = s + " "+ curr; dfs(pos, result, combined, i-s.length()); } } |
This problem is also useful for solving real problems. Assuming you want to analyze the domain names of the top 10k websites. We can use this solution to break the main part of the domain into words and then get a sense of what kinds of websites are popular. I did this a long time ago and found some interesting results. For example, the most frequent words include "news", "tube", "porn", "etc".
<pre><code> String foo = "bar"; </code></pre>
-
Abraham William
-
Sonal Aggarwal
-
German Attanasio Ruiz
-
Yauhen Arnatovich
-
Yauhen Arnatovich
-
HG
-
Debosmit Ray
-
Eugene Arnatovich
-
Dexter
-
antonio081014
-
pig
-
antonio081014
-
antonio081014
-
Jacob Zhang
-
antonio081014