Leetcode: Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. You may assume the dictionary does not contain duplicate words.
Return all such possible sentences.
For example, given
s = "catsanddog"
dict = ["cat", "cats", "and", "sand", "dog"].
A solution is ["cats and dog", "cat sand dog"]
The problem can be solved using Backtracking and memoization.
ca
is not in dictcat
is in dict. Now there is two possibility as it can be seen in the diagram. consider cat
as part of answer and traverse forward with substring sanddog
and ignore cat
and look for next substring which is cats
.memoization
public class WordsBreak2 {
public static void main(String[] args) {
List dict = new ArrayList();
dict.add("cat");
dict.add("cats");
dict.add("and");
dict.add("sand");
dict.add("dogs");
System.out.println(new WordsBreak2().wordBreak("catsanddogs", dict));
}
public List wordBreak(String s, List wordDict) {
if (s == null || s.isEmpty())
return Collections.EMPTY_LIST;
return wordBreak1(s, wordDict, new HashMap());
}
private List wordBreak1(String s, List wordDict, Map> map) {
if (map.containsKey(s)) {
return map.get(s);
}
List res = new ArrayList();
System.out.println(s);
for (int i = 1; i <= s.length(); i++) {
// check if substring is present in dict.
if (wordDict.contains(s.substring(0, i))) {
if (s.substring(i).length() > 0) {
// work with rest of the substring
List r = wordBreak1(s.substring(i), wordDict);
String w = s.substring(0, i);
if (!r.isEmpty()) {
for (String a : r) {
res.add(w + " " + a);
}
}
} else {
res.add(s.substring(0, i));
}
}
}
map.put(s, res);
return res;
}
}
This is one approach but if you run this code in Leetcode you will get Time Limit Exceed error
. For e.g.["a","aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa"]
String s = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
Further optimization can be done by identifying the longest word in the dict and restricting the substring
length not max of dict.
public List wordBreak(String s, List wordDict) {
if (s == null || s.isEmpty() || wordDict.size() == 0)
return Collections.EMPTY_LIST;
int length = getMaxLength(wordDict);
return wordBreak1(s, wordDict, new HashMap(), length);
}
//find max length of word in dict
private int getMaxLength(List wordDict) {
return wordDict.stream().max((o1, o2) ->
Integer.compare(o1.length(), o2.length())).get().length();
}
private List wordBreak1(String s, List wordDict, Map> map, int maxLength) {
if (map.containsKey(s)) {
return map.get(s);
}
List res = new ArrayList();
// restrict for loop with maxLength
for (int i = 1; i <= maxLength && i <= s.length(); i++) {
// check if substring is present in dict.
if (wordDict.contains(s.substring(0, i))) {
if (s.substring(i).length() > 0) {
// work with rest of the substring
List r = wordBreak1(s.substring(i), wordDict, map, maxLength);
String w = s.substring(0, i);
if (!r.isEmpty()) {
for (String a : r) {
res.add(w + " " + a);
}
}
} else {
res.add(s.substring(0, i));
}
}
}
map.put(s, res);
return res;
}
Another approach is to iterate over the dict and see if a word is present. The approach is very similar to above one, but here traversal of dict is done which is faster.
public class Solution {
public List wordBreak(String s, List wordDict) {
if (s == null || s.isEmpty())
return Collections.EMPTY_LIST;
return wordBreak1(s, wordDict, new HashMap());
}
private List wordBreak1(String s, List wordDict, Map> map) {
if (map.containsKey(s)) {
return map.get(s);
}
List res = new ArrayList();
for (int i = 1; i <= s.length(); i++) {
// System.out.println(s.substring(0, i));
if (wordDict.contains(s.substring(0, i))) {
if (s.substring(i).length() > 0) {
List r = wordBreak(s.substring(i), wordDict);
String w = s.substring(0, i);
if (!r.isEmpty()) {
for (String a : r) {
res.add(w + " " + a);
}
}
} else {
res.add(s.substring(0, i));
}
}
}
map.put(s, res);
return res;
}
}