前缀树
推荐例题:
- 208 实现前缀树: 必须掌握,掌握后则其他题型套用即可
- 720 字典中最长的单词
- 692 前K个高频单词
- 208 实现前缀树
例子:我们要实现类似这种数据结构
{
'a': {
'p': {
'p': {
'l': {
'e': {
'isEnd': 1,
'val': 'apple'
}
}
}
}
}
}
// 作者:xing-guang-29
// 链接:https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/208-shi-xian-trie-qian-zhui-shu-by-xing-8ufh8/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题解:
var Trie = function() {
this.children = {};
};
Trie.prototype.insert = function(word) {
let node = this.children;
let val = ""
for (const ch of word) {
val += ch;
if (!node[ch]) {
node[ch] = { };
}
node = node[ch];
}
node.isEnd = true;
node.val = val;
};
Trie.prototype.searchPrefix = function(prefix) {
let node = this.children;
for (const ch of prefix) {
if (!node[ch]) {
return false;
}
node = node[ch];
}
return node;
}
Trie.prototype.search = function(word) {
const node = this.searchPrefix(word);
return node !== undefined && node.isEnd !== undefined;
};
Trie.prototype.startsWith = function(prefix) {
return this.searchPrefix(prefix);
// 这种方式可以取出所有以 prefix 开始的值
// let objSource = this.searchPrefix(prefix);
// const fn = (objSource, result = []) => {
// Object.keys(objSource).forEach(k => {
// let temp = objSource[k]
// if (temp.isEnd) {
// result.push(temp.val)
// }
// if (typeof temp === 'object') {
// fn(temp, result)
// }
// })
// return result
// }
// return fn(objSource, [])
};
// let trie = new Trie();
// trie.insert("apple");
// trie.insert('application')
// trie.insert('apply')
// trie.insert('applyabc')
// let res = trie.startsWith("app")
// console.log('res', res)
//
// res ==> ['apple', 'application', 'apply', 'applyabc']
// 作者:LeetCode-Solution
// 链接:https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shi-xian-trie-qian-zhui-shu-by-leetcode-ti500/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 720 词典中最长的单词
解题思路:
- 前缀树 + dfs
- 哈希表
代码:前缀树 + dfs 方法
var longestWord = function (words) {
const trie = new Trie()
words.forEach(word => {//将所有字符串插入trie中
trie.insert(word)
})
let res = ''
const _helper = (nodes, path) => {
if (path.length > res.length || (res.length === path.length && res > path)) {
res = path
}
//{a:{b1:{c1:{isEnd: true}},b2:{c2:{isEnd: true}}}}
for (const [key, value] of Object.entries(nodes)) {
if (value.isEnd) {//如果当前字符是某一个字符串的结尾
path += key
_helper(value, path)//递归寻找
path = path.slice(0, -1)//回溯
}
}
}
_helper(trie.children, '')//递归寻找那个长度最大的单词
return res
}
var Trie = function() {
this.children = {};
};
Trie.prototype.insert = function(word) {
let nodes = this.children;
for (const ch of word) {//循环word
if (!nodes[ch]) {//当前字符不在子节点中 则创建一个子节点到children的响应位置
nodes[ch] = {};
}
nodes = nodes[ch];//移动指针到下一个字符
}
nodes.isEnd = true;//字符是否结束
};
// 作者:chen-wei-f
// 链接:https://leetcode-cn.com/problems/longest-word-in-dictionary/solution/720-ci-dian-zhong-zui-chang-de-dan-ci-by-2k5k/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
代码:哈希表
/**
* @param {string[]} words
* @return {string}
*/
var longestWord = function(words) {
let res = ''
let set = new Set(words)
for(let w of words){
if (w.length < res.length || w.length === res.length && w > res) continue
let flag = true
for(let i = 1; i < w.length; i++){ // 判断每个前缀是否在words中
if (!set.has( w.slice(0, i) )) {
flag = false
break
}
}
if (flag) res = w
}
return res
};
// 作者:shetia
// 链接:https://leetcode-cn.com/problems/longest-word-in-dictionary/solution/ci-dian-zhong-zui-chang-de-dan-ci-by-she-n4rf/
// 来源:力扣(LeetCode)
- 692 前k个高频单词
解题思路:
- 前缀树
- 哈希表 + 排序
代码:哈希表 + 排序
/**
* @param {string[]} words
* @param {number} k
* @return {string[]}
*/
var topKFrequent = function(words, k) {
const map = {}
for (let i of words) {
map[i] ? map[i] += 1 : map[i] = 1
}
const idx = Object.entries(map).sort(([i1, v1], [i2,v2]) => (v2 - v1) || i1.localeCompare(i2)).slice(0, k)
return idx.map(item => item[0])
};
// topKFrequent(["i", "love", "leetcode", "i", "love", "coding"], 3)