描述
实现一个 MapSum 类,支持两个方法,insert 和 sum:
MapSum()初始化MapSum对象void insert(String key, int val)插入key-val键值对,字符串表示键key,整数表示值val。如果键key已经存在,那么原来的键值对将被替代成新的键值对。int sum(string prefix)返回所有以该前缀prefix开头的键key的值的总和。
示例
输入:inputs = ["MapSum", "insert", "sum", "insert", "sum"]inputs = [[], ["apple", 3], ["ap"], ["app", 2], ["ap"]]输出:[null, null, 3, null, 5]解释:MapSum mapSum = new MapSum();mapSum.insert("apple", 3);mapSum.sum("ap"); // return 3 (apple = 3)mapSum.insert("app", 2);mapSum.sum("ap"); // return 5 (apple + app = 3 + 2 = 5)
提示
1 <= key.length, prefix.length <= 50key和prefix仅由小写英文字母组成1 <= val <= 1000- 最多调用
50次insert和sum
解题思路
前缀树
在经典前缀树算法下做以下改动:
- 用
val记录每个节点的值,对于insert操作,每有一个 char 走到当前节点,节点的val会加上这个字符串的值。 - 用一个
hashMap保存插入的键值对,如果是重复的键,要减去原来的值。 - 对于
sum操作,如果node.children[ch - 'a'] == null,则说明这个字符串不是任何前缀树中的前缀,直接返回0;否则,更新node为node = node.children[ch - 'a'],最后更新res为node.val,返回res;
- 解法最重要的逻辑是:节点的值记录的是前缀树中所有经过这个节点的值的总和,在前缀树中遍历字符串
prefix时,最后一个字符的节点的值就是所有以该前缀prefix开头的键key的值的总和
代码
class MapSum {
MapSum[] children;
int val;
Map<String, Integer> map;
/** Initialize your data structure here. */
public MapSum() {
children = new MapSum[26];
val = 0;
map = new HashMap<>();
}
public void insert(String key, int val) {
MapSum node = this;
for (int i = 0; i < key.length(); i++) {
int index = key.charAt(i) - 'a';
if (node.children[index] == null) {
node.children[index] = new MapSum();
}
if (map.containsKey(key)) {
node.children[index].val -= map.get(key);
}
node.children[index].val += val;
node = node.children[index];
}
map.put(key, val);
}
public int sum(String prefix) {
MapSum node = this;
for (int i = 0; i < prefix.length(); i++) {
int index = prefix.charAt(i) - 'a';
if (node.children[index] == null) {
return 0;
}
node = node.children[index];
}
return node.val;
}
}
