# 472 Concatenated Words

## 472. [Concatenated Words](https://leetcode.com/problems/concatenated-words/description/)

## 1. Question

Given a list of words (**without duplicates**), please write a program that returns all 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.

**Example:**

```
Input: ["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".
```

**Note:**

1. The number of elements of the given array will not exceed`10,000`
2. The length sum of elements in the given array will not exceed`600,000`.
3. All the input string will only include lower case letters.
4. The returned elements order does not matter.

## 2. Implementation

**(1) Trie + DFS**

```java
class Solution {
    class TrieNode {
        char val;
        boolean isWord;
        TrieNode childNode[];

        public TrieNode() {
            childNode = new TrieNode[26];
        }
    }

    class Trie {
        TrieNode root;

        public Trie() {
            root = new TrieNode();
        }

        public void add(String word) {
            if (word == null || word.length() == 0) {
                return;
            }

            TrieNode curNode = root;

            for (char c : word.toCharArray()) {
                int index = c - 'a';

                if (curNode.childNode[index] == null) {
                    curNode.childNode[index] = new TrieNode();
                    curNode.childNode[index].val = c;
                }
                curNode = curNode.childNode[index];
            }
            curNode.isWord = true;
        }

        public boolean search(String word) {
            if (word == null || word.length() == 0) {
                return false;
            }

            TrieNode curNode = root;

            for (char c : word.toCharArray()) {
                int index = c - 'a';

                if (curNode.childNode[index] == null) {
                    return false;
                }
                curNode = curNode.childNode[index];
            }
            return curNode.isWord;
        }
    }

    public List<String> findAllConcatenatedWordsInADict(String[] words) {
        List<String> res = new ArrayList<>();

        if (words == null || words.length == 0) {
            return res;
        }

        Trie trie = new Trie();

        for (String word : words) {
            trie.add(word);
        }

        for (String word : words) {
            if (isConcatenatedWord(word, 0, 0, trie)) {
                res.add(word);
            }
        }
        return res;
    }

    public boolean isConcatenatedWord(String word, int index, int count, Trie trie) {
        // If we are at the end of the current word, check if count is equal to or greater than 1
        // A concatenated word should consist of at least two words
        if (index == word.length() && count >= 2) {
            return true;
        }

        TrieNode curNode = trie.root;

        for (int i = index; i < word.length(); i++) {
            int pos = word.charAt(i) - 'a';

            if (curNode.childNode[pos] == null) {
                return false;
            }

            // if word[0...i] && word[i+1...n] are found in dict, then the current word is concatenated word
            if (curNode.childNode[pos].isWord) {
                if (isConcatenatedWord(word, i + 1, count + 1, trie)) {
                    return true;
                }
            }
            curNode = curNode.childNode[pos];
        }
        return false;
    }
}
```

## 3. Time & Space Complexity

Trie + DFS：时间复杂度O(n \* L^2)， n为word的个数，l为每个word的平均长度, 空间复杂度O(nL)
