Median of Online Data + Sliding Window Max + Sliding Window median
  Subject three problems can be solved with similar recipes
  1. Median of Online Data: https://leetcode.com/problems/find-median-from-data-stream/
Maintain two heaps; on the left side a max heap and right side a min heap (Imagine a seesaw)
On top of left side is always the max element of first half of data
On top of right side is always the min element of the second half of data
if size of two sides is equal : median is mean of top 1 element  of both heaps
If size of one side is bigger by 1: its the element on top of the larger heap the median
If size of one of the side gets bigger to say 2, top the top element and insert to other heap
    def addNum(self, num: int) -> None:
        '''
        boot-strap:
            1. if both are empty add it to min heap
        If both are equal size:
            2. if num is greater than item in maxheap, push to otherside
               else:
                  push to maxheap
        else:
            3. if max heap is of higher size then top of max heap is present median
               3a. if new number if smaller than top of max heap, push to maxheap, and pop/push top of maxheap to minheap
               3b. Else push it to minheap
            4. if min heap is of higher size then top of min heap is present median
               3b. if new numer is larger than top of min heap, then push to minheap, and pop/push top minheap to maxheap
               3b. Else push to maxheap
        '''
        
        if len(self.minheap) == len(self.maxheap) == 0:
            heapq.heappush(self.maxheap, -num)
        else:
            if len(self.minheap) == len(self.maxheap):
                if num > -self.maxheap[0]:
                    heapq.heappush(self.minheap, num)
                else:
                    heapq.heappush(self.maxheap,-num)
            else:
                if len(self.maxheap) > len(self.minheap):
                    if num <= -self.maxheap[0]:
                        heapq.heappush(self.minheap,-heapq.heappushpop(self.maxheap, -num))
                    else:
                        heapq.heappush(self.minheap,num)
                else:
                    if num >= self.minheap[0]:
                        heapq.heappush(self.maxheap,-heapq.heappushpop(self.minheap,num))
                    else:
                        heapq.heappush(self.maxheap,-num)
Finding median is simple
    def findMedian(self) -> float:
        if len(self.maxheap)==len(self.minheap):
            return (-self.maxheap[0]+self.minheap[0])/2
        else:
            if len(self.maxheap) > len(self.minheap):
                return -self.maxheap[0]
            return self.minheap[0]

2 Sliding window maximum
https://leetcode.com/problems/sliding-window-maximum/

here need to maintain only one heap. i.e. a max heap. and data is (number, index)
Trick is we do not need to worry about older(i.e. index is smaller than i-k+1) elements in the heap unless they appear at top of the heap.
if they appear then pop them off.
Number at top is the max
#++++++++++++++++++++++++++
        #keeppushing into heap
        #  at size >= k
        #    while top of heap is older then (i+1-k) pop
        #  peek and push max to result
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        if k == 1:
            return nums
        
        if k == len(nums):
            return [max(nums)]
        
        res=[]
        
        heap=[] #maxheap
        
        for i, num in enumerate(nums):
            heapq.heappush(heap, (-num,i))
            
            while i+1 >= k and heap and heap[0][1] < (i+1-k):
                heapq.heappop(heap)
            if i+1 >= k:
                res.append(-heap[0][0])
        return res

3 Sliding window median:
https://leetcode.com/problems/sliding-window-median/
We use exact recipe as that of median of Online Data problem of maintaining two heaps. And technique of maintaining heap of size of sliding window as second problem above.

    def removefromheap(self,heap, num):
        tmp=[]
        while heap:
            if heap[-1] == num:
                heap.pop()
                break
            else:
                tmp.append(heap.pop())
        while tmp:
            heapq.heappush(heap,tmp.pop())
        
    def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
        res=[]
        for i, num in enumerate(nums):
            self.addNum(num)
            #print(i,self.maxheap, self.minheap)
            if i+1 >= k:
                if i+1 > k:
                    removeNum = nums[i-k]
                    #print("Remove",removeNum)
                    if removeNum == -self.maxheap[0]:
                        heapq.heappop(self.maxheap)
                    elif removeNum==self.minheap[0]:
                        heapq.heappop(self.minheap)
                    elif removeNum > -self.maxheap[0]:
                        self.removefromheap(self.minheap,removeNum)
                    else:
                        self.removefromheap(self.maxheap,-removeNum)
                    if len(self.maxheap) >= len(self.minheap)+2:
                        heapq.heappush(self.minheap, -heapq.heappop(self.maxheap))
                    elif len(self.minheap) >= len(self.maxheap)+2:
                        heapq.heappush(self.maxheap, -heapq.heappop(self.minheap))
                res.append(self.median())
                
        return res
Comments (0)