Leetcode Daily Question 29/09/2024 - 432. All O`one Data Structure

Problem Description:

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.

Solution:

class AllOne:
  def __init__(self):
    self.d = {}
    self.isMinMax = 0
    self.minMax = ""
    
    
  def inc(self, key: str) -> None:
    self.isMinMax = 0
    if key not in self.d:
      self.d[key] = 1
    else:
      self.d[key] += 1
      
      
  def dec(self, key: str) -> None:
    self.isMinMax = 0
    if self.d[key] == 1:
      del self.d[key]
    else:
      self.d[key] -= 1
      
      
  def getMaxKey(self) -> str:
    if not self.d:
      return ""
    if self.isMinMax == 1:
      return self.minMax
    
    self.isMinMax = 1
    
    max_val = list(self.d.values())[0]
    self.minMax = list(self.d.keys())[0]
    
    for key, val in self.d.items():
      if val > max_val:
        max_val = val
        self.minMax = key
        
    return self.minMax
  
  
  def getMinKey(self) -> str:
    if not self.d:
      return ""
    if self.isMinMax == 2:
      return self.minMax
    
    self.minMax = 2
    
    min_val = list(self.d.values())[0]
    self.minMax = list(self.d.keys())[0]
    
    for key, val in self.d.items():
      if val < min_val:
        min_val = val
        self.minMax = key
     
    return self.minMax

Explanation:

The difficult part about this question is the constraint that every operation must be performed on average in O(1) time.

We utilise a dictionary to do this. Naturally, update and insertion are O(1) operations for a dictionary.

To deal with getting the minimum and maximum key, we need create custom memorisation. We can do this using a isMinMax delimiter that will save the state of the current min or max. This way, we do not need to iterate through the items everytime to find min / max. If we repeatedly call the min / max, we retrieve the cached value in memory.

def __init__(self):
  self.d = {}
  self.isMinMax = 0
  self.minMax = ""
  

def inc(self, key: str) -> None:
  self.isMinMax = 0 # Everytime we update the min max may change.
  if key not in self.d:
    self.d[key] = 1
  else:
    self.d[key] += 1
    

def dec(self, key: str) -> None:
  self.isMinMax = 0
  if self.d[key] == 1: # We are guaranteed that this key exists in the dictionary.
    del self.d[key] 
  else:
    self.d[key] -= 1

We shall use 0 to signify undefined, 1 to signify max, and 2 to signify min.

We also use self.minMax to store the current max/min key.

def getMaxKey(self) -> str:
  if not self.d:
    return ""
  if self.isMinMax == 1: # When we repeatedly call this function, the max does not change.
    return self.minMax
  
  self.isMinMax = 1
  
  max_val = list(self.d.values())[0] # Since Python 3.7 the values() method retains insertion order.
  max_key = list(self.d.keys())[0] # So, we use the first set of key/value as our base case for max.
  
  for key, val in self.d.items():
    if val > max_val:
      max_val = val
      max_key = key
      
  return self.minMax


def getMinKey(self) -> str:
  if not self.d:
    return ""
  if self.isMinMax == 2:
    return self.minMax
  
  self.isMinMax = 2
  
  min_val = list(self.d.values())[0]
  min_key = list(self.d.keys())[0]
  
  for key, val in self.d.items():
    if val < max_val:
      min_val = val
      min_key = key
      
  return self.minMax

The time complexity is O(1) as prescribed.

The space complexity is O(n) as we need to potentially store n unique elements given n operations.

The full solution can be found near the top of the page.

Back