208. Implement Trie (Prefix Tree)
题目解释:完成一个triez这样的数据结构,要求其具备有插入(insert)、查找(search)、开始元素(startsWiths)方法。
Example:
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // returns true
trie.search("app"); // returns false
trie.startsWith("app"); // returns true
trie.insert("app");
trie.search("app"); // returns true
注意:
- 所有输入的元素都是小写字母(从a-z)
- 所有的输入都是非空字符串
题目分析:完成一个数据结构,能够实现我们常见的功能。首先映入我们脑海的,也就是最简单的内容,直接按照栈来进行操作,这也是映入我脑海的第一想法,于是乎,code就来了:
class Trie(object):
def __init__(self):
"""
Initialize your data structure here.,维护一个list
"""
self.res=[]
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str
:rtype: None
"""
self.res.append(word)
def search(self, word):
"""
Returns if the word is in the trie.
:type word: str
:rtype: bool
"""
for target in self.res:
if target==word:
return True
return False
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
:type prefix: str
:rtype: bool
"""
for target in self.res:
if len(target)<len(prefix):
continue
if target[:len(prefix)]==prefix:
return True
return False
是不是觉得很开心,一下子就能解决Leetcode上面的medium类型的题?too young too simple.简单是不可能这么简单的,一辈子都不可能这么简单的,那么接下来就是可以学习重点内容了:字典树
what is prefix tree?
简而言之,就是采用字典构成的树,例如,一个保存了8个键的trie结构,"A", "to", "tea", "ted", "ten", "i", "in", and "inn".如下图所示:
字典树主要有如下三点性质:
1. 根节点不包含字符,除根节点意外每个节点只包含一个字符。
2. 从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
3. 每个节点的所有子节点包含的字符串不相同。
有了上面的这个铺垫,我们可以学习一下字典树的实现方式:
【下面的代码是学习Grandyang大佬的】,具体的可以打开链接参考。
class TrieNode {
public:
// Initialize your data structure here.
TrieNode *child[26];
bool isWord;
TrieNode() : isWord(false){
for (auto &a : child) a = NULL;
}
};
class Trie {
public:
Trie() {
root = new TrieNode();
}
// Inserts a word into the trie.
void insert(string s) {
TrieNode *p = root;
for (auto &a : s) {
int i = a - 'a';
if (!p->child[i]) p->child[i] = new TrieNode();
p = p->child[i];
}
p->isWord = true;
}
// Returns if the word is in the trie.
bool search(string key) {
TrieNode *p = root;
for (auto &a : key) {
int i = a - 'a';
if (!p->child[i]) return false;
p = p->child[i];
}
return p->isWord;
}
// Returns if there is any word in the trie
// that starts with the given prefix.
bool startsWith(string prefix) {
TrieNode *p = root;
for (auto &a : prefix) {
int i = a - 'a';
if (!p->child[i]) return false;
p = p->child[i];
}
return true;
}
private:
TrieNode* root;
};
我们也可以采用另外一种字典树的实现方式:结点都是采用字母组成,不会将前面的内容集合起来,即每个Node里面都是单个字符,如‘t’,'e','a'等。同时,我们还对每个Node设计的数据结构还是包含了一个isword的标志位,从而判断是否是我们想要的单词,总体来说,这种实现方式稍微复杂一点,但是理解起来是简单一些的。
class Node(object):
def __init__(self):
self.children = collections.defaultdict(Node)
# 标记符,判断这个内容是否是word
self.isword = False
class Trie(object):
def __init__(self):
"""
Initialize your data structure here.初始化根节点,根节点里面不包含元素
"""
self.root = Node()
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str
:rtype: void
"""
current = self.root
for w in word:
current = current.children[w]
current.isword = True
def search(self, word):
"""
Returns if the word is in the trie.
:type word: str
:rtype: bool
"""
current = self.root
for w in word:
current = current.children.get(w)
if current == None:
return False
return current.isword
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
:type prefix: str
:rtype: bool
"""
current = self.root
for w in prefix:
current = current.children.get(w)
if current == None:
return False
return True