
Problem Statement
The task is to design a specialized map, termed as MapSum
, which facilitates two primary operations based on string keys and their corresponding numerical values. Specifically, the operations are:
- Inserting a key-value pair into the map. Should a key already exist, its value is updated to the newly provided one.
- Calculating the sum of values for all keys that start with a specified prefix.
This necessitates designing a combination of storage and retrieval methods within the MapSum
class:
MapSum()
: Initializes the object environment for storing keys and values.void insert(String key, int val)
: Manages the insertion of the key-value pairs, with provision for overwriting values for existing keys.int sum(string prefix)
: Retrieves and computes the total value for all entries whose keys begin with the provided prefix.
Examples
Example 1
Input:
["MapSum", "insert", "sum", "insert", "sum"] [[], ["apple", 3], ["ap"], ["app", 2], ["ap"]]
Output:
[null, null, 3, null, 5]
Explanation:
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)
Constraints
1 <= key.length, prefix.length <= 50
key
andprefix
consist of only lowercase English letters.1 <= val <= 1000
- At most
50
calls will be made toinsert
andsum
.
Approach and Intuition
Given the operations outlined by the problem, a direct approach using a dictionary (or hash map) can be employed to facilitate quick look-ups and updates for the insert
operation. The structure ensures O(1) average-time complexity for insertions and updates. The key challenge lies in efficiently calculating the sum of values for keys that match a specific prefix, which can naturally lead to a requirement for iterating over the entire key set in the worst case, thereby having a time complexity of O(N), where N is the number of keys.
Example Strategy:
For the initiation of
MapSum
, simply establish an internal dictionary to store key-value pairs.During insertion:
- Check if the key exists in the map.
- If it does, update the value. If not, add the new key-value pair.
For sum calculation:
- Initialize a sum counter to zero.
- Iterate over all keys in the dictionary.
- For each key, if the prefix matches the desired starting substring, add its associated value to the sum counter.
- Finally, return the computed sum.
This method leverages hash map efficiency for insertions and maintains clarity and correctness for prefix-based summation, which remains performant due to the small constraint bounds.
Solutions
- Java
class KeyValueStore {
HashMap<String, Integer> store;
Trie root;
public KeyValueStore() {
store = new HashMap();
root = new Trie();
}
public void insert(String key, int value) {
int difference = value - store.getOrDefault(key, 0);
store.put(key, value);
Trie current = root;
current.score += difference;
for (char c: key.toCharArray()) {
current.children.putIfAbsent(c, new Trie());
current = current.children.get(c);
current.score += difference;
}
}
public int sum(String prefix) {
Trie current = root;
for (char c: prefix.toCharArray()) {
current = current.children.get(c);
if (current == null) return 0;
}
return current.score;
}
}
class Trie {
Map<Character, Trie> children = new HashMap();
int score;
}
The provided Java code implements a combined data structure using both HashMap and Trie to manage a key-value store that supports the insertion of string-integer pairs and the calculation of sums based on string prefixes.
Initialization:
KeyValueStore
class contains aHashMap
namedstore
to keep the keys and their corresponding values.- A
Trie
structure namedroot
is also instantiated. A Trie in this context is used to facilitate fast prefix lookup. - The
Trie
class has aHashMap
namedchildren
to store child nodes and an integerscore
that accumulates the values for all keys sharing the same prefix.
Insert Method:
- The
insert
method first calculates the difference between the new value and the old value (if the key exists, otherwise 0). - It updates the
store
with the new value for the key. - Starting from the root of the
Trie
, it iteratively creates or updates Trie nodes for each character in the key, adjusting the node's score by the computed difference. This ensures that each node maintains a cumulative score of all values for keys sharing the same prefix up to that node.
- The
Sum Method:
- The
sum
method retrieves the cumulative score for all keys that begin with a given prefix. - It traverses the Trie based on the characters in the prefix until the end of the prefix or a missing node is reached.
- If a node corresponding to the end of the prefix is found, its
score
value (which sums all the values of keys with that prefix) is returned.
- The
Utilizing a Trie along with a HashMap optimizes the efficiency of prefix-based queries, making the structure particularly suitable for scenarios where fast lookup, insertion, and prefix-based aggregation are required. Each node in the Trie essentially acts as an aggregation point, storing the sum of all values for keys that traverse through that node. This setup avoids the need for repetitive calculations and improves performance over a simple linear search approach, especially with a large number of keys.
No comments yet.