题目:
实现一个 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)

分析:
该题每个字符串对应一个整数值,看似可以用hashmap来解决,但Hashmap只能实现一对一的查找,根据一个完整字符串来查找它的对应值,无法找到某个前缀开头的所有字符串及其对应的值,需要字符串的前缀查找就可以使用前缀树,定义前缀树步骤和之前题目类似不具体说明,需要注意的是由于每个字符串对应一个数值,因此需要在节点中增加一个整数字段,一个节点对应该字符串最后一个字符,那么该节点的整数字段的值就设为字符串的值。
在找到前缀prefix最后一个字符对应的节点之后,递归地遍历该节点地整个子树,以遍找到所有以前缀开头地字符串并累加它们的值。
具体操作看代码。
代码:

public class MapSum {
public static void main(String[] args) {
MapSum mapSum = new MapSum();
mapSum.insert("apple", 3);
mapSum.sum("ap");
mapSum.insert("app", 2);
int ap = mapSum.sum("ap");
System.out.println(ap);
}
static class TrieNode{
public TrieNode[] children;
public int value;
public TrieNode() {
children = new TrieNode[26];
}
}
private TrieNode root;
public MapSum() {
root = new TrieNode();
}

public void insert(String key, int val) {
TrieNode node = root;
for (int i=0;i < key.length();i++){
char ch = key.charAt(i);
if (node.children[ch-'a'] == null){
node.children[ch - 'a'] = new TrieNode();
}
node = node.children[ch - 'a'];
}
node.value = val;
}

public int sum(String prefix) {
TrieNode node = root;
for (int i=0;i<prefix.length();i++){
char ch = prefix.charAt(i);
//没有找到匹配的前缀,因此返回0
if (node.children[ch - 'a'] == null){
return 0;
}
node = node.children[ch - 'a'];
}
return getSum(node);
}

private int getSum(TrieNode node) {
//递归终止条件,孩子节点为null,返回父节点
if (node == null){
return 0;
}
//该层该节点的值
int result = node.value;
for (TrieNode child:node.children){
//通过递归不断累加
result += getSum(child);
}
//孩子节点遍历完返回result值
return result;
}
}

剑指offer66:单词之和_树