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”.
we can use trie datastructure to solve this problem
This code will not create the right pos[] for the wordDict = {“cat”, “cats”, “and”, “sand”, “dog”, “at”}
Dictionary is a Set that means O(1) for insert and O(1) for lookup. Here is what I did in Javascript http://codepen.io/germanattanasio/pen/MpmRzV
hi mate, I am sorry, but your question does not make sense. Why ? Showing me existing solutions to this problem which are similar to mine does not make my solution to be not mine. You may think I posted kind of “modified” version of existing ones. It is up to you. Now, you ask yourself, How would I benefit at all from posting this solution, which you think it is “modified” version of existing ones ? Or, may be you composed very similar algo to mine and now you think that this is actually yours ? ๐ What drives you this way ?
Btw, can you confirm that my algo matches with every single line of existing ones ? ๐ If so, I promise I will remove my post.
Furthermore, it is a classic problem which has multiple ways to solve. And, I do not think you will find completely “unique” solution which totally differs from existing ones. Will you ? Or, you come out with your “original” solution and post it. Then, you can proudly say (according to your logic): “… It is MY algo”.
Just advice, instead of asking such non-sense questions, you may try to gather all peoples’ thoughts, analyse algos and summarize them. It will help you for your purpose more, rather than you are trying to find out a source of originality, which is in turn pointless as we are all here to learn rather than trying to prove something to someone…
Clarify your question ?
whats your algo ?
There is an issue with type-safety if you use an array of a generic list. Ideally, type-safety is not something you would want to tinker with. A list of ArrayList would be a much better design choice. Working code with couple other fixes: https://github.com/dray92/Programming-Questions/blob/master/leetcode/Word_Break_II.java
Works as magic…
public List solution(String s, String[] dict){
int n = s.length();
Map<Integer, List> map = new HashMap();
for (String d : dict) {
int m = d.length();
for (int i = 0; i n) {
break;
}
if (s.regionMatches(i, d, 0, m)) {
if (!map.containsKey(i)) {
map.put(i, new ArrayList());
}
map.get(i).add(i+m);
}
}
}
StringBuilder sb = new StringBuilder(s);
List res = new ArrayList();
func(0, map, sb, res, 0);
return res;
}
public void func(int key, Map<Integer, List> map, StringBuilder sb, List res, int delta) {
if (!map.containsKey(key)) {
res.add(sb.toString().trim());
return;
}
sb.insert(key+delta, " ");
List lst = map.get(key);
for (int k : lst) {
func(k, map, sb, res, delta+1);
}
if (key > 0) {
sb.deleteCharAt(key+delta);
}
}
How about storing the word start index in t[].
public static int wordBreak(String s, Set dict) {
int[] t = new int[s.length()+1];
//set first to be true, why?
//Because we need initial state
for(int j = 0 ; j < t.length; j++){
t[j] = -1;
}
t[0] = 1;
for(int i=0; i s.length())
continue;
if(t[end] != -1) continue;
if(s.substring(i, end).equals(a)){
t[end] = i;
}
}
}
int start = t[s.length()];
int end = s.length();
while(true){
if(start < 0 || end < 0)
break;
System.out.println(s.substring(start, end));
end = start;
start = t[start];
if(start == 0){
System.out.println(s.substring(start,end));
break;
}
}
return t[s.length()];
}
Thank you.
My 90.97% Java Solution in Leetcode with explanation
https://pingzhblog.wordpress.com/2015/09/17/wordbreak-ii/
BTW, what do you do?
All right. Thank you.
Hey dude, your example is right.
But the given input is a Set, which is not a trie. That means it is bound to behave slowly.
“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa”, [“a”, “aa”, “aaa”, “aaaa”, “aaaaa”, “aaaaaa”, “aaaaaaa”, “aaaaaaaa”]
For this test case, your solution will ETL.
Do you have another solution on this problem?
Thank you.