题目
题目来源:力扣(LeetCode)
设计一个包含一些单词的特殊词典,并能够通过前缀和后缀来检索单词。
实现 WordFilter 类:
WordFilter(string[] words) 使用词典中的单词 words 初始化对象。
f(string prefix, string suffix) 返回词典中具有前缀 prefix 和后缀suffix 的单词的下标。如果存在不止一个满足要求的下标,返回其中 最大的下标 。如果不存在这样的单词,返回 -1 。
示例
输入:
[“WordFilter”, “f”]
[[[“apple”]], [“a”, “e”]]
输出:
[null, 0]
解释:
WordFilter wordFilter = new WordFilter([“apple”]);
wordFilter.f(“a”, “e”); // 返回 0 ,因为下标为 0 的单词的 prefix = “a” 且 suffix = ‘e” 。
思路分析
方法:后缀树+前缀树
往Trie树插入单词时,单词本身包含所有的前缀组合。那么考虑将所有的后缀组合提前,再加一个 特殊字符,组成 后缀+特殊字符+单词 的结构,如 suffix+’#’+word 。那么调用f() 时,只需要查询 suffix+’#’+word 的权重即可。
对于 apple 这个单词,我们可以在单词查找树插入每个后缀,后跟 “#” 和单词。 例如,我们将在单词查找树中插入 ‘#apple’, ‘e#apple’, ‘le#apple’, ‘ple#apple’, ‘pple#apple’, ‘apple#apple’。然后对于 prefix = “ap”, suffix = “le” 这样的查询,我们可以通过查询单词查找树 找到 le#ap
function TrieNode() {
this.next = new Map();
this.weight = 0; //权重,对应单词下标
}
function Trie() {
// 初始化根节点
this.root = new TrieNode();
}
// 插入单词
Trie.prototype.insert = function (word, weight) {
if (!word) return;
let node = this.root;
for (let c of word) {
if (!node.next.has(c)) {
node.next.set(c, new TrieNode());
}
node = node.next.get(c);
node.weight = weight; // 更新weight
}
};
/**
* @param {string[]} words
*/
var WordFilter = function (words) {
this.tree = new Trie();
for (let weight = 0; weight < words.length; weight++) {
let word = words[weight];
let suffix = '';
for (let i = word.length; i >= 0; i--) {
// 单词的后缀
suffix = word.slice(i, word.length);
// 把「后缀 + 特殊字符 + 单词」插入字典树
this.tree.insert(suffix + '#' + word, weight);
}
}
};
/**
* @param {string} prefix
* @param {string} suffix
* @return {number}
*/
WordFilter.prototype.f = function (prefix, suffix) {
let target = suffix + '#' + prefix;
let node = this.tree.root;
for (let c of target) {
if (!node.next.has(c)) return -1;
node = node.next.get(c);
}
return node.weight;
};
/**
* Your WordFilter object will be instantiated and called as such:
* var obj = new WordFilter(words)
* var param_1 = obj.f(prefix,suffix)
*/