Design a data structure to store the strings’ count with the ability to return the strings with minimum and maximum counts.
Implement the AllOne class:
AllOne() Initializes the object of the data structure.
inc(String key) Increments the count of the string key by 1. If key does not exist in the data structure, insert it with count 1.
dec(String key) Decrements the count of the string key by 1. If the count of key is 0 after the decrement, remove it from the data structure. It is guaranteed that key exists in the data structure before the decrement.
getMaxKey() Returns one of the keys with the maximal count. If no element exists, return an empty string "".
getMinKey() Returns one of the keys with the minimum count. If no element exists, return an empty string "".
Note that each function must run in O(1) average time complexity.
We use a doubly linked list (DLL) to maintain the counts of keys in an ordered manner. Each node in this list represents a unique count and holds a set of keys with that count.
A hashmap (dictionary in Python) maps each key to its corresponding node in the DLL, allowing O(1) access to the nodes.
Doubly Linked List (DLL):
Each node in the DLL contains:
freq: The count value.
keys: A set of keys that have this count.
Pointers to the prev and next nodes.
We use sentinel nodes for the head (root.next) and tail (root.prev) to simplify boundary conditions.
Increment (inc):
If the key does not exist, insert it with a count of 1 at the front i.e. using head pointer:
Find or create a node with count 1 at the front of the list.
If the key exists, increment its count:
Move the key to the next node with the incremented count.
If this next node does not exist, create it.
Remove the key from its current node and delete the node if it becomes empty.
Decrement (dec):
The key is guaranteed to exist.
If the key’s count is 1, remove it from the structure.
Otherwise, decrement the count:
Move the key to the previous node with the decremented count.
If this previous node does not exist, create it.
Remove the key from its current node and delete the node if it becomes empty.
Get Max Key (getMaxKey) and Get Min Key (getMinKey):
Directly access the keys in the tail node (root.prev) for the maximum count.
Access keys in the head node (root.next) for the minimum count.