472. Concatenated Words

Given an array of strings words (without duplicates), return all the concatenated words in the given list of words.

A concatenated word is defined as a string that is comprised entirely of at least two shorter words in the given array.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Example 1:

Input: words = ["cat","cats","catsdogcats","dog","dogcatsdog","hippopotamuses","rat","ratcatdogcat"]
Output: ["catsdogcats","dogcatsdog","ratcatdogcat"]
Explanation: "catsdogcats" can be concatenated by "cats", "dog" and "cats"; 
"dogcatsdog" can be concatenated by "dog", "cats" and "dog"; 
"ratcatdogcat" can be concatenated by "rat", "cat", "dog" and "cat".

Example 2:

Input: words = ["cat","dog","catdog"]
Output: ["catdog"]

Constraints:

  • 1 <= words.length <= 104
  • 0 <= words[i].length <= 1000
  • words[i] consists of only lowercase English letters.
  • 0 <= sum(words[i].length) <= 105

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class Solution {
    
    public List<String> findAllConcatenatedWordsInADict(String[] words) {
        List<String> res = new ArrayList<>();
        Set<String> set = new HashSet<>(Arrays.asList(words));
        for (String word: words) {
            if (word.length() == 0) continue;
            set.remove(word);
            boolean[] dp = new boolean[word.length() + 1];
            dp[0] = true;
            for (int i = 1; i < dp.length; i++) {
                for (int j = i - 1; j >= 0; j--) {
                    if (dp[j] && set.contains(word.substring(j, i))) {
                        dp[i] = true;
                        break;
                    }
                }
            }
            if (dp[word.length()]) {
                res.add(word);
            }
            set.add(word);
        }
        return res;
    }    
    
    public List<String> findAllConcatenatedWordsInADict2(String[] words) {
        List<String> res = new ArrayList<>();
        List<String> current = new ArrayList<>();
        Arrays.sort(words, (w1, w2) -> Integer.compare(w1.length(), w2.length()));
        Set<String> set = new HashSet<>(Arrays.asList(words));
        for (String word: words) {
            set.remove(word);
            if (dfs(word, set, "")) {
                res.add(word);
            }
            set.add(word);
        }
        return res;
    }
    boolean dfs(String word, Set<String> set, String prev) {
        if (set.contains(word)) return true;
        for (int i = 1; i < word.length(); i++) {
            String prefix = word.substring(0, i);
            if (set.contains(prefix)) {
               String newPrefix = prev + prefix; 
               set.add(newPrefix); 
               if (dfs(word.substring(prefix.length(), word.length()), set, newPrefix)) {
                   return true;
               }
            }
        }
        return false;
    }
}