2023-01-27 Daily Challenge
Today I have done leetcode's January LeetCoding Challenge with cpp
.
January LeetCoding Challenge 27
Description
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 <= 104
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) <= 105
Solution
auto speedup = [](){
cin.tie(nullptr);
cout.tie(nullptr);
ios::sync_with_stdio(false);
return 0;
}();
struct TrieNode {
TrieNode* children[26];
int count = 0;
bool end = false;
};
void insert(TrieNode *root, const string &word) {
TrieNode *cur = root;
for(auto c : word) {
c -= 'a';
if(!(cur->children[c])) {
cur->children[c] = new TrieNode();
}
cur = cur->children[c];
cur->count += 1;
}
cur->end = true;
}
void remove(TrieNode *root, const string &word) {
TrieNode *cur = root;
vector<TrieNode*> path;
for(auto c : word) {
path.push_back(cur);
c -= 'a';
cur = cur->children[c];
}
cur->end = false;
TrieNode *prev;
for(auto it = word.rbegin(); it != word.rend(); ++it) {
prev = cur;
cur = path.back();
path.pop_back();
int c = *it - 'a';
prev->count -= 1;
if(prev->count == 0) {
// memory leak, but delete will slow down the code
// delete cur->children[c];
cur->children[c] = nullptr;
}
}
}
class Solution {
unordered_map<string, bool> valid;
TrieNode *root;
bool check(const string &word, int pos) {
if(pos && valid.count(word.substr(pos))) {
return valid[word.substr(pos)];
}
TrieNode *cur = root;
for(int i = pos; i < word.length(); ++i) {
int c = word[i] - 'a';
if(!(cur->children[c])) return valid[word] = false;
cur = cur->children[c];
if(cur->end && check(word, i + 1)) return valid[word] = true;
}
return pos && (valid[word] = cur->end);
}
public:
vector<string> findAllConcatenatedWordsInADict(vector<string>& words) {
int minLen = INT_MAX;
set<string> basicWords;
root = new TrieNode();
sort(words.begin(), words.end(), [](const string &a, const string &b) {
return a.length() < b.length();
});
for(const auto &word : words) {
minLen = min<int>(minLen, word.length());
valid[word] = true;
insert(root, word);
}
vector<string> answer;
for(const auto &word: words) {
if(word.length() < minLen * 2) continue;
if(check(word, 0)) {
answer.push_back(word);
remove(root, word);
}
valid[word] = true;
}
return answer;
}
};
// Accepted
// 42/42 cases passed (211 ms)
// Your runtime beats 82.87 % of cpp submissions
// Your memory usage beats 11.55 % of cpp submissions (239 MB)