Advertisement
hoangreal

Find best pin given time window

Oct 21st, 2024 (edited)
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.49 KB | None | 0 0
  1. """Create a user class that insert pin by increasing timestamp and get best pin in a given time window"""
  2.  
  3. """NOT PREFERRED"""
  4.  
  5. def binary_search(start_i, end_i, want_first_true: "bool",
  6.     *, predicate, **kwargs): # -> index | None
  7.     """ Find a predicate s.t:
  8.        1) if pred(mid_i) == True, pred(start_i) == False, pred(end_i) == True
  9.        2) pred(i) tries to find i satisfying problem.
  10.    """
  11.    
  12.     is_reverse = (start_i > end_i)
  13.     step = -1 if is_reverse else 1
  14.    
  15.     left_i = start_i; right_i = end_i
  16.     while left_i * step <= right_i * step:
  17.  
  18.         # [a, b] -> a; [a, b, c] -> b
  19.         mid_i = left_i + (right_i - left_i) // 2
  20.        
  21.         is_mid_satisfy = predicate(mid_i, **kwargs)
  22.         can_move_left = (not is_mid_satisfy)
  23.                
  24.         if can_move_left:
  25.             left_i = mid_i + step
  26.         else:
  27.             right_i = mid_i - step
  28.    
  29.     final_i = left_i if want_first_true else right_i
  30.     return final_i if min(start_i, end_i) <= final_i <= max(start_i, end_i) else None
  31.  
  32. class User:
  33.     def __init__(self):
  34.         self.data = []
  35.  
  36.     def insert_data(self, pin: str, time: int, score: int):
  37.         """ O(n) but amortized O(1)"""
  38.         # You can assume that the time will always be increasing in the data stream
  39.         while self.data and self.data[-1][1] < score:
  40.             self.data.pop()
  41.         self.data.append([time, score, pin])
  42.  
  43.     def get_best_pin(self, current_time: int, window: int) -> str:
  44.         """O(log len(self.data))"""
  45.         # (i) return the pin with maximum score in the window (current_time - window, current_time)
  46.         # (ii) you can assume that current_time will always increase in the future calls
  47.         # (iii) the window size can increase in the future calls, so you can't throw away old data
  48.         # (iv) you don't have to worry about space complexity
  49.        
  50.         target_time = current_time - window
  51.         answer_i = binary_search(0, len(self.data) - 1, True, predicate = lambda i: self.data[i][0] >= target_time)
  52.        
  53.         # please find my solution below
  54.         # return self.data[bisect.bisect(self.data, [current_time - window - 1, 0, ""])][2]
  55.         return self.data[answer_i][2] if answer_i is not None else ""
  56.  
  57. """PREFERRED"""
  58. import heapq
  59. from collections import deque
  60.  
  61. class User:
  62.     def __init__(self):
  63.         # Deque to store pins in the order of their timestamps
  64.         self.deque = deque()  # Each element is (time, score, pin)
  65.        
  66.         # Max heap to store (-score, time, pin) for quick access to the highest score
  67.         self.heap = []  # Each element is (-score, time, pin)
  68.    
  69.     def insert_data(self, pin: str, time: int, score: int):
  70.         """
  71.        Insert a new pin with its timestamp and score.
  72.        Time Complexity: O(log n) due to heap push
  73.        """
  74.         # Append to the deque
  75.         self.deque.append((time, score, pin))
  76.         # Push onto the heap. Negate the score to simulate a max heap.
  77.         heapq.heappush(self.heap, (-score, time, pin))
  78.    
  79.     def get_best_pin(self, current_time: int, window: int) -> str:
  80.         """
  81.        Retrieve the pin with the highest score within the time window.
  82.        
  83.        Time Complexity: O(log n) in the worst case due to heap operations
  84.        """
  85.         target_time = current_time - window
  86.        
  87.         # Remove outdated pins from the deque
  88.         while self.deque and self.deque[0][0] < target_time:
  89.             outdated_pin = self.deque.popleft()
  90.             # Marking the pin as outdated is not necessary since we'll handle it in the heap
  91.             # during retrieval by checking the timestamp
  92.        
  93.         # Clean up the heap by removing pins that are no longer in the deque (outdated)
  94.         while self.heap:
  95.             neg_score, time, pin = self.heap[0]
  96.             if time >= target_time:
  97.                 # The top of the heap is within the time window
  98.                 return pin
  99.             else:
  100.                 # The top pin is outdated, remove it from the heap
  101.                 heapq.heappop(self.heap)
  102.        
  103.         # If no valid pins are found
  104.         return ""
  105.  
  106. # Example:
  107. xyz = User()
  108. data = [("A", 0, 10), ("B", 1, 40), ("C", 2, 30), ("D", 7, 5)]
  109. for pin, time, score in data:
  110.     xyz.insert_data(pin, time, score)
  111.  
  112. print(xyz.get_best_pin(current_time = 7, window = 5)) # you should get C
  113. print(xyz.get_best_pin(current_time = 7, window = 1)) # you should get D
  114. print(xyz.get_best_pin(current_time = 7, window = 7)) # you should get B
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement