Problem: Create a class called KthSmallestTracker. The purpose of the class is to take in new numbers, and to return the kth smallest number that you've seen so far.
Write methods for initializing the class with an integer k, adding a new number, and returning the kth smallest element you've seen so far.
There will always be at least k elements before getKthSmallest is called.
Example:
# initialize with `k = 2`
nums = KthSmallestTracker(2)
nums.add(4)
nums.add(1)
# return k = 2nd smallest element
nums.getKthSmallest() # 4
nums.add(1)
nums.getKthSmallest() # 1
nums.add(2)
nums.getKthSmallest() # 2c = KthSmallestTracker(1)
c.add(3)
c.getKthSmallest()
c.add(2)
c.getKthSmallest()
c.add(1)
c.getKthSmallest()
# We compare the result of every function call when judging.To solve this problem, you need to find the kth smallest element many times.
To do this optimally, you should realize that each time you call getKthSmallest(), many of the numbers will be the same. For example, here are typical numbers that you might track over time:
# tracked numbers over time
# 4, 1
# 4, 1, 1, 2
# 4, 1, 1, 2, 3
# 4, 1, 1, 2, 3, 3
# 4, 1, 1, 2, 3, 3, 5Since many of the same numbers appear each time, you should be able to optimize by remembering something about your past computations.
It's not obvious at first (see below for other solutions), but in this problem you can use a Heap data structure to remember past computations. To do this, you can use a Max-Heap that contains the k smallest numbers you've seen so far. This lets you find the kth smallest number quickly - it's the root node of the heap. It also lets you add numbers quickly.
Here's an example maxheap, where k=6:
When we first create the object, we should store the Heap maxheap, and the size of the heap k for later. Here's the code for doing this:
def __init__(self, k):
# store `maxheap` and `k` for later
self.maxheap = []
self.k = kWe can now write the add function. When we add a new number, we need to update the maxheap so that it has the k smallest elements in it. Here's the code for this:
def add(self, num):
k, maxheap = self.k, self.maxheap
# if heap has fewer than `k` elements, add `num` to heap
if len(maxheap) < k:
heapq.heappush(maxheap, -num)
# else if `num` is smaller than any of the elements in the heap, then replace it out for the root node of the heap
elif num > maxheap[0]:
heapq.heappop(maxheap)
heapq.heappush(maxheap, -num)
# Python doesn't have a Max-Heap, so we implement it using a Min-Heap
# to do this, you negate each value when you add/remove itNow we've created and updated the heap. We can get the kth smallest element, by looking at the root node of the heap:
def getKthSmallest(self):
return -self.maxheap[0] # negative since maxheapHere's the full solution, putting all of the above code together:
import heapq
class KthSmallestTracker:
def __init__(self, k):
self.k = k
self.maxheap = []
def add(self, num):
k, maxheap = self.k, self.maxheap
# add `num` to heap
if len(maxheap) < k:
heapq.heappush(maxheap, -num)
# swap `num` into heap
# making sure heap stays size `k`
elif num > maxheap[0]:
heapq.heappop(maxheap)
heapq.heappush(maxheap, -num)
def getKthSmallest(self):
return -self.maxheap[0] # negative since maxheap
Add Function Time Complexity O(logk) for every number added. This is because the heap contains at most k numbers, which means it has a height of O(log k). So adding to it is O(logk).
Find Kth Smallest Element Time Complexity O(1). The kth smallest element is always at the root node of the heap.
Space Complexity O(k) to store the heap.
Note on Sorted Array solution:
You might have thought to use a Sorted Array to solve this problem (store the smallest k items in a Sorted Array), and that way you can quickly look up and add elements. However, there are shift costs to adding a new smallest item in an Array, making the add time O(k). If you try to use a sorted LinkedList, it's still O(k). You might think to turn the sorted array into a BST, and this does give the optimal solution, but it's quite complicated and you need to worry about balancing the BST which is a whole other difficult problem. Using a Heap is much simpler.