Returns the sum of the values that have a key with a prefix equal to a given string.
Implement the MapSum class:
MapSum() Initializes the MapSum object.
void insert(String key, int val) Inserts the key-val pair into the map. If the key already existed, the original key-value pair will be overridden to the new one.
int sum(string prefix) Returns the sum of all the pairs' value whose key starts with the prefix.
key and prefix consist of only lowercase English letters.
1 <= val <= 1000
At most 50 calls will be made to insert and sum.
Solutions
Solution 1: Hash Table + Trie
We use a hash table \(d\) to store key-value pairs and a trie \(t\) to store the prefix sums of the key-value pairs. Each node in the trie contains two pieces of information:
val: the total sum of the values of the key-value pairs with this node as the prefix
children: an array of length \(26\) that stores the child nodes of this node
When inserting a key-value pair \((key, val)\), we first check if the key exists in the hash table. If it does, the val of each node in the trie needs to subtract the original value of the key and then add the new value. If it does not exist, the val of each node in the trie needs to add the new value.
When querying the prefix sum, we start from the root node of the trie and traverse the prefix string. If the current node's child nodes do not contain the character, it means the prefix does not exist in the trie, and we return \(0\). Otherwise, we continue to traverse the next character until we finish traversing the prefix string and return the val of the current node.
In terms of time complexity, the time complexity of inserting a key-value pair is \(O(n)\), where \(n\) is the length of the key. The time complexity of querying the prefix sum is \(O(m)\), where \(m\) is the length of the prefix.
The space complexity is \(O(n \times m \times C)\), where \(n\) and \(m\) are the number of keys and the maximum length of the keys, respectively; and \(C\) is the size of the character set, which is \(26\) in this problem.
classTrie:def__init__(self):self.children:List[Trie|None]=[None]*26self.val:int=0definsert(self,w:str,x:int):node=selfforcinw:idx=ord(c)-ord('a')ifnode.children[idx]isNone:node.children[idx]=Trie()node=node.children[idx]node.val+=xdefsearch(self,w:str)->int:node=selfforcinw:idx=ord(c)-ord('a')ifnode.children[idx]isNone:return0node=node.children[idx]returnnode.valclassMapSum:def__init__(self):self.d=defaultdict(int)self.tree=Trie()definsert(self,key:str,val:int)->None:x=val-self.d[key]self.d[key]=valself.tree.insert(key,x)defsum(self,prefix:str)->int:returnself.tree.search(prefix)# Your MapSum object will be instantiated and called as such:# obj = MapSum()# obj.insert(key,val)# param_2 = obj.sum(prefix)
classTrie{privateTrie[]children=newTrie[26];privateintval;publicvoidinsert(Stringw,intx){Trienode=this;for(inti=0;i<w.length();++i){intidx=w.charAt(i)-'a';if(node.children[idx]==null){node.children[idx]=newTrie();}node=node.children[idx];node.val+=x;}}publicintsearch(Stringw){Trienode=this;for(inti=0;i<w.length();++i){intidx=w.charAt(i)-'a';if(node.children[idx]==null){return0;}node=node.children[idx];}returnnode.val;}}classMapSum{privateMap<String,Integer>d=newHashMap<>();privateTrietrie=newTrie();publicMapSum(){}publicvoidinsert(Stringkey,intval){intx=val-d.getOrDefault(key,0);d.put(key,val);trie.insert(key,x);}publicintsum(Stringprefix){returntrie.search(prefix);}}/** * Your MapSum object will be instantiated and called as such: * MapSum obj = new MapSum(); * obj.insert(key,val); * int param_2 = obj.sum(prefix); */
classTrie{public:Trie():children(26,nullptr){}voidinsert(string&w,intx){Trie*node=this;for(charc:w){c-='a';if(!node->children[c]){node->children[c]=newTrie();}node=node->children[c];node->val+=x;}}intsearch(string&w){Trie*node=this;for(charc:w){c-='a';if(!node->children[c]){return0;}node=node->children[c];}returnnode->val;}private:vector<Trie*>children;intval=0;};classMapSum{public:MapSum(){}voidinsert(stringkey,intval){intx=val-d[key];d[key]=val;trie->insert(key,x);}intsum(stringprefix){returntrie->search(prefix);}private:unordered_map<string,int>d;Trie*trie=newTrie();};/** * Your MapSum object will be instantiated and called as such: * MapSum* obj = new MapSum(); * obj->insert(key,val); * int param_2 = obj->sum(prefix); */
typetriestruct{children[26]*trievalint}func(t*trie)insert(wstring,xint){for_,c:=rangew{c-='a'ift.children[c]==nil{t.children[c]=&trie{}}t=t.children[c]t.val+=x}}func(t*trie)search(wstring)int{for_,c:=rangew{c-='a'ift.children[c]==nil{return0}t=t.children[c]}returnt.val}typeMapSumstruct{dmap[string]intt*trie}funcConstructor()MapSum{returnMapSum{make(map[string]int),&trie{}}}func(this*MapSum)Insert(keystring,valint){x:=val-this.d[key]this.d[key]=valthis.t.insert(key,x)}func(this*MapSum)Sum(prefixstring)int{returnthis.t.search(prefix)}/** * Your MapSum object will be instantiated and called as such: * obj := Constructor(); * obj.Insert(key,val); * param_2 := obj.Sum(prefix); */
classTrie{children:Trie[];val:number;constructor(){this.children=newArray(26);this.val=0;}insert(w:string,x:number){letnode:Trie=this;for(constcofw){consti=c.charCodeAt(0)-97;if(!node.children[i]){node.children[i]=newTrie();}node=node.children[i];node.val+=x;}}search(w:string):number{letnode:Trie=this;for(constcofw){consti=c.charCodeAt(0)-97;if(!node.children[i]){return0;}node=node.children[i];}returnnode.val;}}classMapSum{d:Map<string,number>;t:Trie;constructor(){this.d=newMap();this.t=newTrie();}insert(key:string,val:number):void{constx=val-(this.d.get(key)??0);this.d.set(key,val);this.t.insert(key,x);}sum(prefix:string):number{returnthis.t.search(prefix);}}/** * Your MapSum object will be instantiated and called as such: * var obj = new MapSum() * obj.insert(key,val) * var param_2 = obj.sum(prefix) */
classTrie{constructor(){this.children=newArray(26);this.val=0;}insert(w,x){letnode=this;for(constcofw){consti=c.charCodeAt(0)-97;if(!node.children[i]){node.children[i]=newTrie();}node=node.children[i];node.val+=x;}}search(w){letnode=this;for(constcofw){consti=c.charCodeAt(0)-97;if(!node.children[i]){return0;}node=node.children[i];}returnnode.val;}}varMapSum=function(){this.d=newMap();this.t=newTrie();};/** * @param {string} key * @param {number} val * @return {void} */MapSum.prototype.insert=function(key,val){constx=val-(this.d.get(key)??0);this.d.set(key,val);this.t.insert(key,x);};/** * @param {string} prefix * @return {number} */MapSum.prototype.sum=function(prefix){returnthis.t.search(prefix);};/** * Your MapSum object will be instantiated and called as such: * var obj = new MapSum() * obj.insert(key,val) * var param_2 = obj.sum(prefix) */
publicclassTrie{privateTrie[]children=newTrie[26];privateintval;publicvoidInsert(stringw,intx){Trienode=this;for(inti=0;i<w.Length;++i){intidx=w[i]-'a';if(node.children[idx]==null){node.children[idx]=newTrie();}node=node.children[idx];node.val+=x;}}publicintSearch(stringw){Trienode=this;for(inti=0;i<w.Length;++i){intidx=w[i]-'a';if(node.children[idx]==null){return0;}node=node.children[idx];}returnnode.val;}}publicclassMapSum{privateDictionary<string,int>d=newDictionary<string,int>();privateTrietrie=newTrie();publicMapSum(){}publicvoidInsert(stringkey,intval){intx=val-(d.ContainsKey(key)?d[key]:0);d[key]=val;trie.Insert(key,x);}publicintSum(stringprefix){returntrie.Search(prefix);}}/** * Your MapSum object will be instantiated and called as such: * MapSum obj = new MapSum(); * obj.Insert(key,val); * int param_2 = obj.Sum(prefix); */