All O`one Data Structure
Problem Statement
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.
Example 1:
Input
["AllOne", "inc", "inc", "getMaxKey", "getMinKey", "inc", "getMaxKey", "getMinKey"]
[[], ["hello"], ["hello"], [], [], ["leet"], [], []]
Output
[null, null, null, "hello", "hello", null, "hello", "leet"]
Explanation
AllOne allOne = new AllOne();
allOne.inc("hello");
allOne.inc("hello");
allOne.getMaxKey(); // return "hello"
allOne.getMinKey(); // return "hello"
allOne.inc("leet");
allOne.getMaxKey(); // return "hello"
allOne.getMinKey(); // return "leet"
Constraints:
- 1 <= key.length <= 10
key
consists of lowercase English letters.- It is guaranteed that for each call to dec, key is existing in the data structure.
- At most 5 * 104 calls will be made to inc, dec, getMaxKey, and getMinKey.
Code
Python
class Block(object):
def __init__(self, val=0):
self.val = val
self.keys = set()
self.before = None
self.after = None
def remove(self):
self.before.after = self.after
self.after.before = self.before
self.before, self.after = None, None
def insert_after(self, new_block):
old_after = self.after
self.after = new_block
new_block.before = self
new_block.after = old_after
old_after.before = new_block
class AllOne(object):
def __init__(self):
self.begin = Block() # sentinel
self.end = Block() # sentinel
self.begin.after = self.end
self.end.before = self.begin
self.mapping = {} # key to block
def inc(self, key):
if not key in self.mapping: # find current block and remove key
current_block = self.begin
else:
current_block = self.mapping[key]
current_block.keys.remove(key)
if current_block.val + 1 != current_block.after.val: # insert new block
new_block = Block(current_block.val + 1)
current_block.insert_after(new_block)
else:
new_block = current_block.after
new_block.keys.add(key) # update new_block
self.mapping[key] = new_block # ... and mapping of key to new_block
if not current_block.keys and current_block.val != 0: # delete current block if not seninel
current_block.remove()
def dec(self, key):
if not key in self.mapping:
return
current_block = self.mapping[key]
del self.mapping[key] # could use self.mapping.pop(key)
current_block.keys.remove(key)
if current_block.val != 1:
if current_block.val - 1 != current_block.before.val: # insert new block
new_block = Block(current_block.val - 1)
current_block.before.insert_after(new_block)
else:
new_block = current_block.before
new_block.keys.add(key)
self.mapping[key] = new_block
if not current_block.keys: # delete current block
current_block.remove()
def getMaxKey(self):
if self.end.before.val == 0:
return ""
key = self.end.before.keys.pop() # pop and add back to get arbitrary (but not random) element
self.end.before.keys.add(key)
return key
def getMinKey(self):
if self.begin.after.val == 0:
return ""
key = self.begin.after.keys.pop()
self.begin.after.keys.add(key)
return key