Description
You are given two integers, m and k, and a stream of integers. You are tasked to implement a data structure that calculates the MKAverage for the stream.
The MKAverage can be calculated using these steps:
- If the number of the elements in the stream is less than
myou should consider the MKAverage to be-1. Otherwise, copy the lastmelements of the stream to a separate container. - Remove the smallest
kelements and the largestkelements from the container. - Calculate the average value for the rest of the elements rounded down to the nearest integer.
Implement the MKAverage class:
MKAverage(int m, int k)Initializes the MKAverage object with an empty stream and the two integersmandk.void addElement(int num)Inserts a new elementnuminto the stream.int calculateMKAverage()Calculates and returns the MKAverage for the current stream rounded down to the nearest integer.
Example 1:
Input
["MKAverage", "addElement", "addElement", "calculateMKAverage", "addElement", "calculateMKAverage", "addElement", "addElement", "addElement", "calculateMKAverage"]
[[3, 1], [3], [1], [], [10], [], [5], [5], [5], []]
Output
[null, null, null, -1, null, 3, null, null, null, 5]
Explanation
MKAverage obj = new MKAverage(3, 1);
obj.addElement(3); // current elements are [3]
obj.addElement(1); // current elements are [3,1]
obj.calculateMKAverage(); // return -1, because m = 3 and only 2 elements exist.
obj.addElement(10); // current elements are [3,1,10]
obj.calculateMKAverage(); // The last 3 elements are [3,1,10].
// After removing smallest and largest 1 element the container will be [3].
// The average of [3] equals 3/1 = 3, return 3
obj.addElement(5); // current elements are [3,1,10,5]
obj.addElement(5); // current elements are [3,1,10,5,5]
obj.addElement(5); // current elements are [3,1,10,5,5,5]
obj.calculateMKAverage(); // The last 3 elements are [5,5,5].
// After removing smallest and largest 1 element the container will be [5].
// The average of [5] equals 5/1 = 5, return 5
Constraints:
3 <= m <= 1051 < k*2 < m1 <= num <= 105- At most
105calls will be made toaddElementandcalculateMKAverage.
Solutions
Solution 1: Ordered Set + Queue
We can maintain the following data structures or variables:
- A queue q of length m, where the head of the queue is the earliest added element, and the tail of the queue is the most recently added element;
- Three ordered sets, namely lo, mid, hi, where lo and hi store the smallest k elements and the largest k elements respectively, and mid stores the remaining elements;
- A variable s, maintaining the sum of all elements in mid;
- Some programming languages (such as Java, Go) additionally maintain two variables size1 and size3, representing the number of elements in lo and hi respectively.
When calling the addElement(num) function, perform the following operations in order:
- If lo is empty, or num ≤ max(lo), then add num to lo; otherwise if hi is empty, or num ≥ min(hi), then add num to hi; otherwise add num to mid, and add the value of num to s.
- Next, add num to the queue q. If the length of the queue q is greater than m at this time, remove the head element x from the queue q, then choose one of lo, mid or hi that contains x, and remove x from this set. If the set is mid, subtract the value of x from s.
- If the length of lo is greater than k, then repeatedly remove the maximum value max(lo) from lo, add max(lo) to mid, and add the value of max(lo) to s.
- If the length of hi is greater than k, then repeatedly remove the minimum value min(hi) from hi, add min(hi) to mid, and add the value of min(hi) to s.
- If the length of lo is less than k and mid is not empty, then repeatedly remove the minimum value min(mid) from mid, add min(mid) to lo, and subtract the value of min(mid) from s.
- If the length of hi is less than k and mid is not empty, then repeatedly remove the maximum value max(mid) from mid, add max(mid) to hi, and subtract the value of max(mid) from s.
When calling the calculateMKAverage() function, if the length of q is less than m, return -1, otherwise return s⁄m - 2k.
In terms of time complexity, each call to the addElement(num) function has a time complexity of O(log m), and each call to the calculateMKAverage() function has a time complexity of O(1). The space complexity is O(m).
PythonJavaC++Go
class MKAverage: def __init__(self, m: int, k: int): self.m = m self.k = k self.s = 0 self.q = deque() self.lo = SortedList() self.mid = SortedList() self.hi = SortedList() def addElement(self, num: int) -> None: if not self.lo or num <= self.lo[-1]: self.lo.add(num) elif not self.hi or num >= self.hi[0]: self.hi.add(num) else: self.mid.add(num) self.s += num self.q.append(num) if len(self.q) > self.m: x = self.q.popleft() if x in self.lo: self.lo.remove(x) elif x in self.hi: self.hi.remove(x) else: self.mid.remove(x) self.s -= x while len(self.lo) > self.k: x = self.lo.pop() self.mid.add(x) self.s += x while len(self.hi) > self.k: x = self.hi.pop(0) self.mid.add(x) self.s += x while len(self.lo) < self.k and self.mid: x = self.mid.pop(0) self.lo.add(x) self.s -= x while len(self.hi) < self.k and self.mid: x = self.mid.pop() self.hi.add(x) self.s -= x def calculateMKAverage(self) -> int: return -1 if len(self.q) < self.m else self.s // (self.m - 2 * self.k) # Your MKAverage object will be instantiated and called as such: # obj = MKAverage(m, k) # obj.addElement(num) # param_2 = obj.calculateMKAverage()(code-box)
Solution 2
Python
class MKAverage: def __init__(self, m: int, k: int): self.m = m self.k = k self.sl = SortedList() self.q = deque() self.s = 0 def addElement(self, num: int) -> None: self.q.append(num) if len(self.q) == self.m: self.sl = SortedList(self.q) self.s = sum(self.sl[self.k : -self.k]) elif len(self.q) > self.m: i = self.sl.bisect_left(num) if i < self.k: self.s += self.sl[self.k - 1] elif self.k <= i <= self.m - self.k: self.s += num else: self.s += self.sl[self.m - self.k] self.sl.add(num) x = self.q.popleft() i = self.sl.bisect_left(x) if i < self.k: self.s -= self.sl[self.k] elif self.k <= i <= self.m - self.k: self.s -= x else: self.s -= self.sl[self.m - self.k] self.sl.remove(x) def calculateMKAverage(self) -> int: return -1 if len(self.sl) < self.m else self.s // (self.m - self.k * 2) # Your MKAverage object will be instantiated and called as such: # obj = MKAverage(m, k) # obj.addElement(num) # param_2 = obj.calculateMKAverage()(code-box)
