题目描述
实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。
示例:
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // 返回 true
trie.search("app"); // 返回 false
trie.startsWith("app"); // 返回 true
trie.insert("app");
trie.search("app"); // 返回 true
说明:
你可以假设所有的输入都是由小写字母 a-z 构成的。
保证所有输入均为非空字符串。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/implement-trie-prefix-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
熟悉一下 Trie 的概念就可以了。
https://medium.com/basecs/trying-to-understand-tries-3ec6bede0014
复杂度分析
- 时间复杂度:$O(L)$,L 是字符串长度,
insert
search
startsWith
操作都是。 - 空间复杂度:$O(M^{L})$,L 是字符串长度,M 是字符集中字符个数,如本题中 M 就是 26。
代码
TypeScript Code
class TrieNode { value: string; children: Array<TrieNode | null>; constructor(value) { this.value = value; this.children = Array(26); } } class Trie { private root: TrieNode; constructor() { this.root = this._getTrieNode(''); } private _getTrieNode(value: string): TrieNode { return new TrieNode(value); } private _char2Index(char: string): number { return char.toLowerCase().charCodeAt(0) - 97; } insert(word: string): void { let crawl: TrieNode = this.root; for (let char of word) { const index: number = this._char2Index(char); if (!crawl.children[index]) { crawl.children[index] = this._getTrieNode(''); } crawl = crawl.children[index]; } crawl.value = word; } search(word: string): boolean { let crawl: TrieNode = this.root; for (let char of word) { const index: number = this._char2Index(char); if (!crawl.children[index]) return false; crawl = crawl.children[index]; } return crawl.value === word; } startsWith(prefix: string): boolean { let crawl: TrieNode = this.root; for (let char of prefix) { const index: number = this._char2Index(char); if (!crawl.children[index]) return false; crawl = crawl.children[index]; } return true; } } /** * Your Trie object will be instantiated and called as such: * var obj = new Trie() * obj.insert(word) * var param_2 = obj.search(word) * var param_3 = obj.startsWith(prefix) */
JavaScript Code
class TrieNode { constructor(val) { this.value = val; this.pointers = Array(26); } } class Trie { constructor() { this.root = this._getTrieNode(''); } /** * @param {string} val */ _getTrieNode(val) { return new TrieNode(val); } /** * @param {string} char * @returns {number} */ _char2Index(char) { return char.toLowerCase().charCodeAt(0) - 97; } /** * Inserts a word into the trie. * @param {string} word * @return {void} */ insert(word) { let crawl = this.root; for (let char of word) { const index = this._char2Index(char); if (!crawl.pointers[index]) { crawl.pointers[index] = this._getTrieNode(''); } crawl = crawl.pointers[index]; } // Store the word in the last TrieNode as an end mark. crawl.value = word; } /** * Returns if the word is in the trie. * @param {string} word * @return {boolean} */ search(word) { let crawl = this.root; for (let char of word) { const index = this._char2Index(char); if (!crawl.pointers[index]) return false; crawl = crawl.pointers[index]; } // If it has a stored value, it is the last TrieNode, i.e., the desired word is found. // Otherwise, the word doesn't exist in Trie. return !!crawl.value; } /** * Returns if there is any word in the trie that starts with the given prefix. * @param {string} prefix * @return {boolean} */ startsWith(prefix) { let crawl = this.root; for (let char of prefix) { const index = this._char2Index(char); if (!crawl.pointers[index]) return false; crawl = crawl.pointers[index]; } return true; } }
输入输出
Nodejs
const __main__ = function () { const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); console.log('******输入******'); rl.prompt(); const lines = []; rl.on('line', line => lines.push(line)); rl.on('close', () => { console.log('\n******输出******'); const test = (operations, params) => { if (operations[0] === 'Trie') { const trie = new Trie(); const output = [null]; for (let i = 1; i < operations.length; i++) { const res = trie[operations[i]](...params[i]); output.push(res === void 0 ? null : res); } console.log(output); } else { console.log(Array(operations.length).fill(null)); } }; while (lines.length >= 2) { const params = lines.splice(0, 2); test(...params.map(el => JSON.parse(el))); } }); };