题源
知识点
前缀树
- 前缀树或者说是字典树,都是一个意思。
- 它是一个多叉树
- Trie的核心思想是
空间换时间
。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。 - 前缀树,对于大数据很有用,利用字符串的
公共前缀来减少查询时间
,最大限度地减少和字符串的直接比较
。 - 这道题目的多叉树设计如下:
思路
- 就如上图的一样,
isEnd判断是否存在单词
,其余26个是一个指针数组
,用空间换时间。
+实现插入、搜索单词、搜索前缀
。 - 如果存在这个单词,则将isEnd置为true,其他的时候都是为false。
代码
Python
class Trie:
def __init__(self):
self.children = [None] * 26
self.isEnd = False
def insert(self, word: str) -> None:
node = self
for w in word:
index = ord(w) - ord('a')
if not node.children[index]:
node.children[index] = Trie()
node = node.children[index]
node.isEnd = True
def search(self, word: str) -> bool:
node = self
for w in word:
index = ord(w) - ord('a')
if not node.children[index]:
return False
node = node.children[index]
return node.isEnd
def startsWith(self, prefix: str) -> bool:
node = self
for w in prefix:
index = ord(w) - ord('a')
if not node.children[index]:
return False
node = node.children[index]
return True
# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)
执行用时:180 ms, 在所有 Python3 提交中击败了51.04%的用户
内存消耗:33.6 MB, 在所有 Python3 提交中击败了37.97%的用户
JavaScript
var Trie = function() {
this.isEnd = false
this.children = new Array(26).fill(null)
};
/**
* @param {string} word
* @return {void}
*/
Trie.prototype.insert = function(word) {
let node = this
for(let w of word){
let index = w.charCodeAt(0) - 'a'.charCodeAt(0)
if(!node.children[index]) node.children[index] = new Trie()
node = node.children[index]
}
node.isEnd = true
};
/**
* @param {string} word
* @return {boolean}
*/
Trie.prototype.search = function(word) {
let node = this
for(let w of word){
let index = w.charCodeAt(0) - 'a'.charCodeAt(0)
if(! node.children[index]) return false
node = node.children[index]
}
return node.isEnd
};
/**
* @param {string} prefix
* @return {boolean}
*/
Trie.prototype.startsWith = function(prefix) {
let node = this
for(let w of prefix){
let index = w.charCodeAt(0) - 'a'.charCodeAt(0)
if(! node.children[index]) return false
node = node.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)
*/
执行用时:180 ms, 在所有 JavaScript 提交中击败了59.66%的用户
内存消耗:65.3 MB, 在所有 JavaScript 提交中击败了12.86%的用户
Java
class Trie {
private boolean isEnd;
private final Trie[] children;
public Trie() {
isEnd = false;
children = new Trie[26];
}
public void insert(String word) {
Trie node = this;
int wordLen = word.length();
for(int i = 0; i < wordLen; i++){
int index = word.charAt(i) - 'a';
if(node.children[index] == null){
node.children[index] = new Trie();
}
node = node.children[index];
}
node.isEnd = true;
}
public boolean search(String word) {
Trie node = this;
int wordLen = word.length();
for(int i = 0; i < wordLen; i++){
int index = word.charAt(i) - 'a';
if(node.children[index] == null){
return false;
}
node = node.children[index];
}
return node.isEnd;
}
public boolean startsWith(String prefix) {
Trie node = this;
int wordLen = prefix.length();
for(int i = 0; i < wordLen; i++){
int index = prefix.charAt(i) - 'a';
if(node.children[index] == null){
return false;
}
node = node.children[index];
}
return true;
}
}
/**
* Your Trie object will be instantiated and called as such:
* Trie obj = new Trie();
* obj.insert(word);
* boolean param_2 = obj.search(word);
* boolean param_3 = obj.startsWith(prefix);
*/
执行用时:36 ms, 在所有 Java 提交中击败了38.80%的用户
内存消耗:49.6 MB, 在所有 Java 提交中击败了76.47%的用户
C
typedef struct {
bool isEnd;
struct Trie *children[26];
} Trie;
Trie* trieCreate() {
Trie * t = (Trie *)malloc(sizeof(Trie));
t->isEnd = false;
for(int i = 0; i < 26; i++) t->children[i] = NULL;
return t;
}
void trieInsert(Trie* obj, char * word) {
int wordLen = strlen(word);
for(int i = 0; i < wordLen; i++){
int index = word[i] - 'a';
if(obj->children[index] == NULL){
obj->children[index] = trieCreate();
}
obj = obj->children[index];
}
obj->isEnd = true;
}
bool trieSearch(Trie* obj, char * word) {
int wordLen = strlen(word);
for(int i = 0; i < wordLen; i++){
int index = word[i] - 'a';
if(obj->children[index] == NULL){
return false;
}
obj = obj->children[index];
}
return obj->isEnd;
}
bool trieStartsWith(Trie* obj, char * prefix) {
int wordLen = strlen(prefix);
for(int i = 0; i < wordLen; i++){
int index = prefix[i] - 'a';
if(obj->children[index] == NULL){
return false;
}
obj = obj->children[index];
}
return true;
}
void trieFree(Trie* obj) {
for(int i = 0; i < 26; i++){
if(obj->children[i] != NULL){
trieFree(obj->children[i]);
}
}
free(obj);
}
/**
* Your Trie struct will be instantiated and called as such:
* Trie* obj = trieCreate();
* trieInsert(obj, word);
* bool param_2 = trieSearch(obj, word);
* bool param_3 = trieStartsWith(obj, prefix);
* trieFree(obj);
*/
执行用时:60 ms, 在所有 C 提交中击败了65.12%的用户
内存消耗:38.1 MB, 在所有 C 提交中击败了69.14%的用户