【题目】
Implement a trie with insert, search, and startsWith methods.
Note:
You may assume that all inputs are consist of lowercase letters a-z.
【解析】
题目要求实现Prefix Tree(前缀树)的insert、search和startWith方法,所以必须先知道什么是前缀树
【前缀树】
Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,例如,英文字母的字典树是一个26叉树,数字的字典树是一个10叉树。
Trie的核心思想是用空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。当然,如果系统中存在大量字符串且这些字符串基本没有公共前缀,则相应的trie树将非常消耗内存,这也是trie树的一个缺点。
含有键为”A”、”to”、”tea”、”ted”、”ten”、”i”、”in”和”inn”的trie示例。
性质
根节点不包含字符,除根节点外每一个节点都只包含一个字符;
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
每个节点的所有子节点包含的字符都不相同。
效率
对于有n个英文字母的串来说,在内部结点中定位指针所需要花费O(d)时间,d为字母表的大小,英文为26。由于在上面的算法中内部结点指针定位使用了数组随机存储方式,因此时间复杂度降为了O(1)。但是如果是中文字,下面在实际应用中会提到。因此我们在这里还是用O(d)。 查找成功的时候恰好走了一条从根结点到叶子结点的路径。因此时间复杂度为O(d*n)。
但是,当查找集合X中所有字符串两两都不共享前缀时,trie中出现最坏情况。除根之外,所有内部结点都自由一个子结点。此时的查找时间复杂度蜕化为O(d*(n^2)
【java实现】
class TrieNode {
TrieNode[] children = new TrieNode[26];
String path="";//存储一条路径,即对应一个字符串
// Initialize your data structure here.
public TrieNode() {
}
}
public class Trie {
private TrieNode root;
public Trie() {
root = new TrieNode();
}
// Inserts a word into the trie.
public void insert(String word) {
TrieNode node = this.root;
for(char c : word.toCharArray()){
if(node.children[c-'a']==null){
node.children[c-'a'] = new TrieNode();
}
node = node.children[c-'a'];
}
node.path = word;
}
// Returns if the word is in the trie.
public boolean search(String word) {
TrieNode node = this.root;
for(char c:word.toCharArray()){
if(node.children[c-'a']==null){
return false;
}
node = node.children[c-'a'];
}
return node.path.equals(word);
}
// Returns if there is any word in the trie
// that starts with the given prefix.
public boolean startsWith(String prefix) {
TrieNode node = this.root;
for(char c:prefix.toCharArray()){
if(node.children[c-'a']==null){
return false;
}
node = node.children[c-'a'];
}
return true;
}
}
// Your Trie object will be instantiated and called as such:
// Trie trie = new Trie();
// trie.insert("somestring");
// trie.search("key");