前缀树是N叉树的一种形式,常用于存储字符串,树中每一个节点表示一个字符。
前缀树重要的存在价值是搜索速度,典型的利用空间换时间,时间复杂度为O(n),n是树的深度。
上图中存储了四个单词:am、bad、be、so,位于叶子节点,叶子节点一定为词,但词不一定位于叶子节点。除了存储词的节点外,其余节点称为前缀。如ba,在树中并不是一个词,但他是bad词的前缀,前缀的重要作用就是减少存储空间,具有相同前缀的不同单词,只需存储差异部分,大大减少了空间的存储。
我所喜欢的数据结构:
public class TrieNode {
public boolean isWord;
public HashMap<Character, TrieNode> nexts = new HashMap<Character, TrieNode>();
}
Trie常见的操作:
插入
private void insert(String word, TrieNode root) {
TrieNode node = root;
for (int i = 0; i < word.length(); i++) {
if (node.nexts.get(word.charAt(i)) == null) {
//没有前缀
node.nexts.put(word.charAt(i), new TrieNode());
}
node = node.nexts.get(word.charAt(i));//切记切换到子节点,否则全部存在了一层
}
node.isWord = true;//标记单词存储结束,其余节点为前缀
}
查找单词
private boolean search(String word, TrieNode root) {
TrieNode node = root;
for (int i = 0; i < word.length(); i++) {
if (node.nexts.get(word.charAt(i)) == null) {
return false;//中途查找失败,就失败
}
node = node.nexts.get(word.charAt(i));//切换到下一层
}
return node.isWord;//查找到了但不一定是单词,有可能是其他单词的前缀,因此需要判断
}
查找前缀
public boolean startsWith(String prefix) {
char[] chars=prefix.toCharArray();
TrieNode node=root;
for(int i=0;i<chars.length;i++){
if(node.nexts.get(chars[i])==null){
return false;//没查完就到顶了,失败
}else{
node=node.nexts.get(chars[i]);//查找下一层
}
}
return true;//查找到了一定是前缀,与查找单词不同
}
Map Sum Pairs
https://leetcode.com/explore/learn/card/trie/148/practical-application-i/1058/
这个题目实在是翻译不出来啊!题意:插入多个单词(apple、app)给每一个词赋值apple=3、app=2,当输入前缀ap时,返回以ap为前缀的所有单词值的和。
Example:
Input: insert(“apple”, 3), Output: Null
Input: sum(“ap”), Output: 3
Input: insert(“app”, 2), Output: Null
Input: sum(“ap”), Output: 5
public int sum(String prefix) {
char[] chars=prefix.toCharArray();
TrieNode node=root;