very simple and clean solutions on Java (2 approaches)
\n\tApproach #1 Backtracking:\n    \n\tpublic List findAllConcatenatedWordsInADict(String[] words) {\n      Set hash = new HashSet<>(Arrays.asList(words));\n\n 
\n\tApproach #1 Backtracking:\n    \n\tpublic List<String> findAllConcatenatedWordsInADict(String[] words) {\n      Set<String> hash = new HashSet<>(Arrays.asList(words));\n\n      List<String> list = new ArrayList<>();\n      for (String word : words) {\n        if (concatenated(word, 0, hash)) {\n          list.add(word);\n        }\n      }\n\n      return list;\n    }\n\n    private boolean concatenated(String word, int i, Set<String> words) {\n      StringBuilder sb = new StringBuilder();\n\n      for (int k = i; k < word.length(); k++) {\n        sb.append(word.charAt(k));\n        if (words.contains(sb.toString())) {\n          if (concatenated(word, k + 1, words)) {\n            return true;\n          }\n        }\n      }\n\n      return sb.length() > 0 && sb.length() < word.length() && words.contains(sb.toString());\n    }\n\t\n\tApproach #2 Trie + DFS:\n\t\n\tpublic List<String> findAllConcatenatedWordsInADict(String[] words) {\n      Trie trie = new Trie();\n\n      for (String word : words) {\n        trie.addWord(word);\n      }\n\n      List<String> solution = new ArrayList<>();\n\n      for (String word : words) {\n        if (isConcatenated(trie.root, word, 0)) {\n          solution.add(word);\n        }\n      }\n\n      return solution;\n    }\n\n    private boolean isConcatenated(TrieNode root, String word, int index) {\n      int counter = 0;\n\n      TrieNode node = root;\n\n      for (int i = index; i < word.length(); i++) {\n        counter++;\n\n        char ch = word.charAt(i);\n\n        if (!node.map.containsKey(ch)) {\n          return false;\n        }\n\n        node = node.map.get(ch);\n        if (node.isWord) {\n          if (i == word.length() - 1 && counter < word.length()) {\n            return true;\n          } else if (i < word.length() - 1 && isConcatenated(root, word, i + 1)) {\n            return true;\n          }\n        }\n      }\n\n      return false;\n    }\n\n    private static class Trie {\n      private TrieNode root = new TrieNode();\n\n      private void addWord(String word) {\n        TrieNode node = root;\n\n        for (int i = 0; i < word.length(); i++) {\n          char ch = word.charAt(i);\n\n          if (node.map.containsKey(ch)) {\n            node = node.map.get(ch);\n          } else {\n            node.map.put(ch, new TrieNode());\n            node = node.map.get(ch);\n          }\n        }\n\n        node.isWord = true;\n      }\n    }\n\n    private static class TrieNode {\n      Map<Character, TrieNode> map = new HashMap<>();\n      boolean isWord = false;\n    }
['Backtracking', 'Depth-First Search', 'Trie']