题目(难度:中等):
实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。
示例:
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // 返回 true
trie.search("app"); // 返回 false
trie.startsWith("app"); // 返回 true
trie.insert("app");
trie.search("app"); // 返回 true
代码思想:
前缀树的特点是每个字符串都是从头节点开始连接,包括查询、删除等操作也都是从头节点开始。前缀树的每个边可以看作是一个字符,每个节点带有这个边出现的次数信息,即添加了几次。叶子节点也带有叶子节点出现的次数信息。
代码实现:
public class TrieNode{
public int path;
public int end;
public TrieNode[] nexts;
public TrieNode(){
path = 0;
end = 0;
nexts = new TrieNode[26]; //按照字母
}
}
private TrieNode root;
public Solution208() {
root = new TrieNode();
}
public void insert(String word) {
if (word == null || word.length() == 0) return;
char[] str = word.toCharArray();
int index = 0;
TrieNode head = root;
for (int i = 0; i < str.length; i++) {
index = str[i] - 'a';
if (head.nexts[index] == null) {
head.nexts[index] = new TrieNode();
}
head = head.nexts[index];
head.path++;
}
head.end++;
}
public boolean search(String word) {
if (word == null || word.length() == 0) return false;
char[] str = word.toCharArray();
int index = 0;
TrieNode head = root;
for (int i = 0; i < str.length; i++) {
index = str[i] - 'a';
if (head.nexts[index] == null) {
return false;
}
head = head.nexts[index];
}
if(head.end != 0) return true;
else return false;
}
public boolean startwith(String prefix) {
if (prefix == null || prefix.length() == 0) return false;
char[] str = prefix.toCharArray();
int index = 0;
TrieNode head = root;
for (int i = 0; i < str.length; i++) {
index = str[i] - 'a';
if (head.nexts[index] == null) {
return false;
}
head = head.nexts[index];
}
return true;
}
public void delete(String word) {
if (word == null || word.length() == 0 || !search(word)) return;
char[] str = word.toCharArray();
int index = 0;
TrieNode head = root;
for (int i = 0; i < str.length; i++) {
index = str[i] - 'a';
if (--head.nexts[index].path == 0) {
head.nexts[index] = null;
return;
}
head = head.nexts[index];
}
head.nexts[index].end--;
}
测试用例:
算法分析:
时间复杂度O(n),额外空间复杂度O(1)