掘金团队号上线,助你 Offer 临门! 点击 查看详情
实现 Trie (前缀树)(题号208)
题目
Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。
请你实现 Trie 类:
Trie()
初始化前缀树对象。void insert(String word)
向前缀树中插入字符串word
。boolean search(String word)
如果字符串word
在前缀树中,返回true
(即,在检索之前已经插入);否则,返回false
。boolean startsWith(String prefix)
如果之前已经插入的字符串word
的前缀之一为prefix
,返回true
;否则,返回false
。
示例:
输入
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
输出
[null, null, true, false, true, null, true]
解释
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
提示:
1 <= word.length, prefix.length <= 2000
word
和prefix
仅由小写英文字母组成insert
、search
和startsWith
调用次数 总计 不超过3 * 104
次
链接
解释
这题啊,这题考的是字典树,理解了字典树的关系其实就很简单了,JavaScript
的实现其实很简单,没啥可说的,就是一层层的嵌套对象即可。
自己的答案(对象)
/**
* Initialize your data structure here.
*/
var Trie = function() {
this.root = Object.create(null)
};
/**
* Inserts a word into the trie.
* @param {string} word
* @return {void}
*/
Trie.prototype.insert = function(word) {
var node = this.root
for (const chart of word) {
if (!node[chart]) node[chart] = Object.create(null)
node = node[chart]
}
node.isWord = true
};
Trie.prototype.check = function(word, isWord = false) {
var node = this.root
for (const chart of word) {
if (!node[chart]) return false
node = node[chart]
}
return isWord ? !!node.isWord : true
};
/**
* Returns if the word is in the trie.
* @param {string} word
* @return {boolean}
*/
Trie.prototype.search = function(word) {
return this.check(word, true)
};
/**
* Returns if there is any word in the trie that starts with the given prefix.
* @param {string} prefix
* @return {boolean}
*/
Trie.prototype.startsWith = function(prefix) {
return this.check(prefix)
};
insert
的时候循环字母,然后按顺序一层层的嵌套下去,得到了一个包含所有字母的对象,并且在字母的末端添加isWord
标识符,用来表示单词是否完结,用来区分search
查找和startsWith
查找。
但是这个方法的性能一直不好,不知道为啥,尤其是在内存消耗上,一直处于后30%,思考了好久,发现问题原来是Object.create(null)
搞得鬼,之间换成{}
屁事没有,内存和耗时直接80%以上,令人发指的问题。
这题就没什么更好的方法了,再优化也就是在写法上有一些简写,把两行简化成一行之类的操作,为了一点点的速度牺牲可读性笔者觉得不合适,这又不是具体的比赛,这里就不说了。
自己的答案(Map)
用对象的时候必然会想到Map
,于是笔者又用Map
写了一版👇:
/**
* Initialize your data structure here.
*/
var Trie = function() {
this.root = new Map()
};
/**
* Inserts a word into the trie.
* @param {string} word
* @return {void}
*/
Trie.prototype.insert = function(word) {
var node = this.root
for (const w of word) {
if (!node.has(w)) node.set(w, new Map())
node = node.get(w)
}
node.set('isWord', true)
};
/**
* Returns if the word is in the trie.
* @param {string} word
* @return {boolean}
*/
Trie.prototype.search = function(word) {
var node = this.root
for (const w of word) {
if (!node.has(w)) return false
node = node.get(w)
}
return node.get('isWord') || false
};
/**
* Returns if there is any word in the trie that starts with the given prefix.
* @param {string} prefix
* @return {boolean}
*/
Trie.prototype.startsWith = function(prefix) {
var node = this.root
for (const p of prefix) {
if (!node.has(p)) return false
node = node.get(p)
}
return true
};
用时直接干到了99%以上,就是内存差了点,只有50%左右,可以理解。
更好的方法
无
PS:想查看往期文章和题目可以点击下面的链接:
这里是按照日期分类的👇
经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇
有兴趣的也可以看看我的个人主页👇