前缀树(Trie树),又称字典树、单词查找树。常用于文本词频统计,可以最大限度的减少字符串比对的频率。
大概的结构如下:
每个结点都维护着一个next结点数组(普通链表维护的是next结点),大概形式如下:
class TrieNode {
public int val;
public TrieNode[]next = new TrieNode[26];
}
除了next数组外,可能还有其它的成员变量,例如上面的val,可根据具体场景定义。
next的下标是字母与'a'的差值,
'a' - 'a' = 0
'b' - 'a' = 1
'c' - 'a' = 2
......
实战:LeetCode:677. 键值映射
题目:
实现一个 MapSum 类,支持两个方法,insert 和 sum:
MapSum() 初始化 MapSum 对象
void insert(String key, int val) 插入 key-val 键值对,字符串表示键 key ,整数表示值 val 。如果键 key 已经存在,那么原来的键值对将被替代成新的键值对。
int sum(string prefix) 返回所有以该前缀 prefix 开头的键 key 的值的总和。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/map-sum-pairs
实现方式:
class MapSum {
class TrieNode {
public int val;
public TrieNode[]next = new TrieNode[26];
}
Map<String, Integer>map;
TrieNode root;
public MapSum() {
map = new HashMap<>();
root = new TrieNode();
}
public void insert(String key, int val) {
int div = val - map.getOrDefault(key, 0);
map.put(key, val);
TrieNode node = root;
for(int i = 0; i < key.length(); i++) {
char c = key.charAt(i);
if(node.next[c - 'a'] == null) {
node.next[c - 'a'] = new TrieNode();
}
node = node.next[c - 'a'];
node.val = div + node.val;
}
}
public int sum(String prefix) {
if(prefix == null) {
return 0;
}
TrieNode p = root;
for(int i = 0; i < prefix.length(); i++) {
if(p == null) {
break;
}
p = p.next[prefix.charAt(i) - 'a'];
}
return p == null ? 0 : p.val;
}
}
/**
* Your MapSum object will be instantiated and called as such:
* MapSum obj = new MapSum();
* obj.insert(key,val);
* int param_2 = obj.sum(prefix);
*/
div用于存储字符替换所带来的差值,val用于存储符合前缀的单词总和,时间复杂度为O(n)。