这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战
题目
实现一个 MapSum 类,支持两个方法,insert 和 sum:
MapSum()初始化MapSum对象void insert(String key, int val)插入key-val键值对,字符串表示键key,整数表示值val。如果键key已经存在,那么原来的键值对将被替代成新的键值对。int sum(string prefix)返回所有以该前缀prefix开头的键key的值的总和。
示例
输入:
["MapSum", "insert", "sum", "insert", "sum"]
[[], ["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
解题思路
前缀树
对于insert方法,很多方式都能实现,但是后面的sum方法,要求的是找到以前缀prefix开头的所有键的值总和,这时候就得采用前缀树来实现来,采用前缀树我们可以快速找到需要的前缀及其后续所有节点,再通过深度搜索来汇总所有的值并返回即可。
前缀树模版
class PrefixTree{
// 定义一个数组,每个字符对应一个位置
private PrefixTree[] next;
// 值
private int val;
// 判断是否为完整单词
private boolean end;
public PrefixTree(){
// 小写字母,占用26位,如果有其它字母,这里需要调整
this.next = new PrefixTree[26];
}
/**
* 插入字符串
*/
public void insert(String word, int val){
// 先获取当前对象
PrefixTree node = this;
// 遍历字符,按照字符串中字符顺序建立字符链
for(char w : word.toCharArray()){
// 判断其如果还未创建当前字符对象,则创建对象
if(null == node.next[w - 'a']){
node.next[w - 'a'] = new PrefixTree();
}
// 指针后移
node = node.next[w - 'a'];
}
// 保存结果
node.val = val;
// 标记完整字符路径
node.end = true;
}
/**
* 搜索字符串
*/
public boolean search(String word){
// 获取对象
PrefixTree node = this;
// 遍历字符串
for(char w : word.toCharArray()){
// 如果对应字符对象未创建,表示该字符串未添加
if(null == node.next[w - 'a']){
return false;
}
// 指针后移
node = node.next[w - 'a'];
}
// 这里根据需要选择返回 val 或者 end
return node.end;
}
}
代码实现
class MapSum {
private MapSum[] next;
private int val;
public MapSum() {
this.next = new MapSum[26];
}
/**
* 创建对应路径,保存结果
*/
public void insert(String key, int val) {
MapSum node = this;
for(char k : key.toCharArray()){
if(node.next[k - 'a'] == null){
node.next[k - 'a'] = new MapSum();
}
node = node.next[k - 'a'];
}
node.val = val;
}
/**
* 获取该前缀及其后续节点的值的总和
*/
public int sum(String prefix) {
MapSum node = this;
for(char pre : prefix.toCharArray()){
// 没有该前缀对应路径则直接返回0
if(node.next[pre - 'a'] == null){
return 0;
}else{
// 指针后移
node = node.next[pre - 'a'];
}
}
// 求和
return sum(node);
}
/**
* 求得该节点及其后续节点的值的总和
*/
public int sum(MapSum node){
int sum = node.val;
for(int i = 0; i < 26; ++i){
// 节点不为空则继续递归向下搜索
if(node.next[i] != null){
sum += sum(node.next[i]);
}
}
// 返回总和
return sum;
}
}
复杂度分析
- 时间复杂度:
- 空间复杂度:
最后
文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!
如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!