Solution: Time-Based Key-Value Store
Let's solve the Time-Based Key-Value Store problem using Custom Data Structures.
Statement#
Implement a data structure that can store multiple values of the same key at different timestamps and retrieve the key’s value at a certain timestamp.
You’ll need to implement the TimeStamp class. This class has the following functions:
-
Init(): This function initializes the values dictionary and timestamp dictionary.
-
Set Value(key, value, timestamp): This function stores the key and value at any given timestamp.
-
Get Value(key, timestamp): This function returns the value set for this key at the specified timestamp.
Note: When a query requests the value of a key at a timestamp that is more recent than the most recent entry for that key, our data structure should return the value corresponding to the most recent timestamp.
Constraints:
-
key.length,value.length keyandvalueconsist of lowercase English letters and digits.-
timestamp - At most calls will be made to Set Value and Get Value.
- All the timestamps
timestampof Set Value are strictly increasing.
Solution#
So far, you have probably brainstormed some approaches and have an idea of how to solve this problem. Let’s explore some of these approaches and figure out which to follow based on considerations such as time complexity and implementation constraints.
Naive approach#
The naive approach uses three individual lists to store the key, value, and timestamp, each in a separate list. To set a value, we’ll simply append key, value, and timestamp in their respective lists. To get a value, we’ll perform a linear search and search for a specific value for the given timestamp and key throughout the list.
The time complexity to set a value is , whereas to get a value is , where represents the total number of values in a list. However, the space complexity of the naive approach is .
Optimized approach using binary search#
The key idea is to minimize the time complexity by using the binary search instead of linear search. We can use the binary search to implement our logic and can decrease the time complexity to a great extent.
We will use the two dictionaries. The first dictionary, values_dict, stores the values against a specific key. The second dictionary, timestamps_dict, stores the timestamps corresponding to the same key to keep track of the values stored at a specific timestamp.
Set Value(key, value, timestamp): This function adds the key with the value for the given timestamp. For this, we check if the key already exists in the values_dict dictionary.
- If the
keyexists and the providedvalueis not equal to the last value stored in thevalues_dictfor this key, we append thevalueandtimestampto the lists associated with that key in thevalues_dictandtimestamps_dict, respectively. - If the
keydoes not exist in thevalues_dictdictionary, it creates a new entry in both thevalues_dictandtimestamps_dictdictionaries.
Get Value(key, timestamp): This function returns the value set previously, with the highest timestamp for the respective key. This function uses the search_index function, which uses the binary search in its implementation. To implement this function, we initialize the left and right variables as starting and ending positions of the timestamps_dict dictionary. We then find the middle position and move these pointers to get the required value. If the required value is less than the middle value, we increment the right pointer. Otherwise, we increment the left pointer.
We check the following conditions to get the required value:
-
We first verify whether or not the required
keyexists. If it does not exist, then return the empty string. -
If the
keyexists, we check the following conditions:- If the given timestamp does not exist but is greater than the timestamp that was set previously, it returns the value associated with the nearest smaller timestamp.
- If the given timestamp exists, it returns the value associated with the given key and timestamp.
Here’s a demonstration of the algorithm above:
1 of 7
2 of 7
3 of 7
4 of 7
5 of 7
6 of 7
7 of 7
Let’s look at the code for this solution below:
Solution summary#
To recap, the solution to this problem can be divided into the following parts:
-
Set Value(): This first checks if the key already exists in the dictionary. If the key exists and the provided value is different from the last stored value for that key, it appends the new value and timestamp to respective lists. If the key is not present, it creates a new entry in both the value and timestamp dictionaries.
-
Get Value(): This checks if the key exists in the dictionary. If it does, it uses binary search to find the index of the rightmost occurrence of the given timestamp in the timestamps list. If an index is found, it returns the corresponding value. Otherwise, it returns an empty string.
Time complexity#
The time complexity to set the value in the hash map is . The binary search takes time to search the element, so the time complexity to get the element will be .
Space complexity#
The space complexity of the algorithm above is , where n is the total number of values because we’re calculating the hash map for all the values.
Time-Based Key-Value Store
Implement LRU Cache