3
Trie *suffixLink; // this is where it will fallback to when a letter can't5
int id = -1; // this id will be 0 or greater if it matches a word6
map<char, Trie *> next;12
int uniqueIds = 0; // used to count all the unique words discovered and as13
// part of the Trie id system15
StreamChecker(vector<string> &words) {18
// standard trie traversal but keeping track of new words via id system19
for (string &word : words) {22
if (p->next.find(c) == p->next.end()) {23
p->next.insert({c, new Trie()});33
for (pair<char, Trie *> itr : root->next) {35
itr.second->suffixLink = root;38
// BFS traversal to build the automaton40
Trie *curr = q.front();42
for (pair<char, Trie *> e : curr->next) {44
Trie *node = e.second;46
Trie *ptr = curr->suffixLink;47
while (ptr != root && ptr->next.find(c) == ptr->next.end()) {48
ptr = ptr->suffixLink;50
// find the next suffixLink if it matches the current character or51
// fallback to the root52
node->suffixLink = ptr->next.find(c) != ptr->next.end() ? ptr->next.at(c) : root;54
// if the current suffixLink happens to also be a word we should store55
// its id to make it quick to find56
if (node->suffixLink->id != -1) {57
node->id = node->suffixLink->id;62
// the query ptr will now track every new streamed character and can be used63
// to quickly find words67
bool query(char letter) {68
// if the next letter can't be found and we're not at the root, we'll trace69
// back until we find the longest suffix that matches70
while (queryPtr != root && queryPtr->next.find(letter) == queryPtr->next.end()) {71
queryPtr = queryPtr->suffixLink;74
queryPtr->next.find(letter) != queryPtr->next.end() ? queryPtr->next.at(letter) : root;75
// if any word is found it will have an id that isn't -176
return queryPtr->id != -1;