Concatenated Words ⧉
We want to find out which words from words
can be formed by concatenating existing words from words
. One way to do this is to first build a trie from words
, then
perform a recursive DFS on the trie to see if a given word can be formed by tracing the trie to a completed word, starting again from the root, and tracing down to the end of another word.
Complexity is O(n*m), where n is the number of words and m is the length of a given word. The trie approach is not necessarily very cache-friendly. We also spend a considerable amount of time allocating trie nodes even though the bounds of the problem are known up front. Might be neat to figure out how to statically allocate a trie.
_63#include <array>_63#include <functional>_63#include <string>_63#include <vector>_63_63using namespace std;_63_63struct Trie {_63 array<Trie *, 26> next{};_63 bool terminus = false;_63_63 void add_word(const string &word) {_63 Trie *curr = this;_63 for (char letter : word) {_63 if (curr->next[letter - 'a'] == nullptr) {_63 curr->next[letter - 'a'] = new Trie();_63 }_63 curr = curr->next[letter - 'a'];_63 }_63 curr->terminus = true;_63 }_63_63 bool has_concatenated(const string &word) {_63 const int n = word.length();_63 function<bool(int, Trie *, bool)> rec = [&](int start, Trie *curr,_63 bool hasBranched) {_63 for (int i = start; i < n; ++i) {_63 if (curr->next[word[i] - 'a'] == nullptr) {_63 return false;_63 }_63 curr = curr->next[word[i] - 'a'];_63 if (curr->terminus && i < n) {_63 // only valid if we branch at least once_63 if (i + 1 == n && hasBranched)_63 return true;_63 bool branch = rec(i + 1, this, true);_63 if (branch) {_63 return true;_63 }_63 }_63 }_63 return false;_63 };_63_63 return rec(0, this, false);_63 }_63};_63_63class Solution {_63public:_63 vector<string> findAllConcatenatedWordsInADict(vector<string> &words) {_63 Trie root{};_63 for (const auto &word : words) {_63 root.add_word(word);_63 }_63 vector<string> concatenated;_63 for (const auto &word : words) {_63 if (root.has_concatenated(word))_63 concatenated.push_back(word);_63 }_63 return concatenated;_63 }_63};
If you found this solution helpful, consider leaving a star!