1
+ class Solution {
2
+ /*
3
+ Similar to word break solution. TC- O(b^d) since each word can be broken down
4
+ on an avg in b parts.
5
+ */
6
+ HashSet <String > set ;
7
+ public List <String > findAllConcatenatedWordsInADict (String [] words ) {
8
+ set = new HashSet <>();
9
+ List <String > res = new ArrayList <>();
10
+ if (words .length == 0 || words .length == 1 ) return res ;
11
+ for (String w : words ) {
12
+ set .add (w );
13
+ }
14
+ for (String w : words ) {
15
+ if (isConcat (w )) {
16
+ res .add (w );
17
+ }
18
+ }
19
+ return res ;
20
+ }
21
+
22
+ public boolean isConcat (String word ) {
23
+ int len = word .length ();
24
+ for (int i =1 ; i <len ; i ++) {
25
+ String prefix = word .substring (0 ,i );
26
+ String suffix = word .substring (i );
27
+ if (set .contains (prefix ) && (set .contains (suffix ) || isConcat (suffix ))) {
28
+ return true ;
29
+ }
30
+ }
31
+ return false ;
32
+ }
33
+ }
34
+
35
+
36
+ /*
37
+ String#hashCode() takes O(L) for the first computation.
38
+ Because we use #substring() a lot here, we cannot utilize the hashCode cache,
39
+ so dict.contains(word.substring(j, i)) in the inner loop takes O(L), which make it a triple loop over length L,
40
+ that's O(L^3), and the overall is O(N*L^3).
41
+ */
42
+
43
+ class Solution {
44
+ public List <String > findAllConcatenatedWordsInADict (String [] words ) {
45
+ List <String > res = new ArrayList <>();
46
+ HashSet <String > set = new HashSet <>();
47
+ // we can only make combinations from smaller words. Hence, we sort
48
+
49
+ Arrays .sort (words , new Comparator <String >() {
50
+ public int compare (String s1 , String s2 ) {
51
+ return s1 .length () - s2 .length ();
52
+ }
53
+ });
54
+ // or Arrays.sort(words, (a,b) -> a.length() - b.length());
55
+ HashSet <String > preWords = new HashSet <>();
56
+ for (int i =0 ; i <words .length ; i ++) {
57
+ if (canForm (words [i ], preWords )) {
58
+ res .add (words [i ]);
59
+ }
60
+ preWords .add (words [i ]);
61
+ }
62
+ return res ;
63
+ }
64
+
65
+ public boolean canForm (String word , HashSet <String > dict ) {
66
+ if (dict .isEmpty ()) return false ;
67
+ boolean [] dp = new boolean [word .length () + 1 ];
68
+ dp [0 ] = true ;
69
+
70
+ for (int i =1 ; i <=word .length ();i ++) {
71
+ for (int j =0 ; j <i ; j ++) {
72
+ if (dp [j ] && dict .contains (word .substring (j , i ))) {
73
+ dp [i ] = true ;
74
+ break ;
75
+ }
76
+ }
77
+ }
78
+ return dp [word .length ()];
79
+ }
80
+ }
0 commit comments