Skip to main content

Concatenated Words


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.

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 <= 10^4
  • 1 <= words[i].length <= 30
  • words[i] consists of only lowercase English letters.
  • All the strings of words are unique.
  • 1 <= sum(words[i].length) <= 10^5

Try this Problem on your own or check similar problems:

  1. Word Break II
Solution:
class Solution {
class Trie {
public class TrieNode{
TrieNode[] children;
boolean isWord = false;
public TrieNode(){
children = new TrieNode[26];
}
}

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

public void insert(String word) {
TrieNode iter = root;
for(int i = 0; i < word.length(); ++i){
char letter = word.charAt(i);
if(iter.children[letter - 'a'] == null){
iter.children[letter - 'a'] = new TrieNode();
}
iter = iter.children[letter - 'a'];
}
iter.isWord = true;
}

private boolean isConcatenated(String word, TrieNode iter, int index, int numberOfWords){
if(index == word.length()) return numberOfWords > 1;

for(int i = index; i < word.length(); ++i){
char c = word.charAt(i);
if(iter.children[c - 'a'] == null) return false;

iter = iter.children[c - 'a'];
if(iter.isWord && isConcatenated(word, root, i + 1, numberOfWords + 1)){
return true;
}
}

return false;
}
}



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

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

for(String word: words){
if(trie.isConcatenated(word, trie.root, 0, 0)) result.add(word);
}

return result;
}
}

Time/Space Complexity:
  • Time Complexity: O(nk*n)
  • Space Complexity: O(nk)

Explanation:

We use the same Trie approach we have already used in Implement Trie (Prefix Tree) and Longest Word in Dictionary. It takes n * k time to build and traverse the trie where n is the number of words while k is the average or maximum length of given words so the time complexity is O(nk), we have the same for space complexity since the number of nodes will be equal to sum of all word lengths (we can take average or maximum length word to define upper boundary). For the time complexity we also we have the multiplier n since we perform traversal n times (we traverse for every word) and in the worst-case scenario we would be visiting all nodes in the trie for each traversal. The bulk of the algorithm is isConcatenated search where try to break the current word in other words in the trie while counting the total number of words we used numberOfWords.