class TrieNode {
constructor() {
this.children = new Map();
this.isWord = false;
}
}
class Trie {
constructor() {
this.root = new TrieNode();
}
insert(word) {
let node = this.root;
for (const char of word) {
if (!node.children.has(char)) {
node.children.set(char, new TrieNode());
}
node = node.children.get(char);
}
node.isWord = true;
}
longestWord() {
let result = "";
const dfs = (node, path) => {
if (node !== this.root && !node.isWord) return;
if (path.length > result.length || (path.length === result.length && path < result)) {
result = path;
}
for (const [char, child] of [...node.children.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
dfs(child, path + char);
}
};
dfs(this.root, "");
return result;
}
}
const words = ["a", "app", "ap", "apply", "apple", "appl"];
const trie = new Trie();
for (const word of words) {
trie.insert(word);
}
console.log(trie.longestWord());if (!node.children.has(char)) { node.children.set(char, new TrieNode()); }
Create new child node if character path does not exist
node = node.children.get(char);
Advance node pointer to child node for current character
Mark current node as end of a valid word
if (node !== this.root && !node.isWord) return;
Stop DFS if current node is not root and not end of a word (prefix invalid)
if (path.length > result.length || (path.length === result.length && path < result)) { result = path; }
Update longest word if current path is longer or lex smaller if equal length
for (const [char, child] of [...node.children.entries()].sort((a, b) => a[0].localeCompare(b[0]))) { dfs(child, path + char); }
Traverse children in alphabetical order to ensure lex order