295. Find Median from Data Stream

295. Find Median from Data Stream

Problem Solving - Day 42

ยท

3 min read

Hello, reader ๐Ÿ‘‹๐Ÿฝ ! Welcome to day 42 of the series on Problem Solving. Through this series, I aim to pick up at least one question everyday and share my approach for solving it.

Today, I will be picking up LeetCode's daily challenge problem: 295. Find Median from Data Stream.


๐Ÿค” Problem Statement

  • Implement the MedianFinder class:

    • MedianFinder() initializes the MedianFinder object.
    • void addNum(int num) adds the integer num from the data stream to the data structure. -double findMedian() returns the median of all elements so far. Answers within 10-5 of the actual answer will be accepted.
  • E.g.:

    • nums = [1,1,2] => 2
    • nums = [0,0,1,1,1,2,2,3,3,4] => 5
    • nums = [2,3,4] => 3

๐Ÿ’ฌ Thought Process - Priority Queue

  • One of the naive ways to solve is to use a list and maintain the list sorted. But then every time a new value is added sorting would take O(n logn) which is inefficient.
  • Hence we can make use of a priority queue to bring down the complexity to O(logn).
  • The idea is to split the data into two halves using priority queues. The first half is stored in a max heap and the second half in a min heap.
  • We also ensure that all the values in the max heap are less than every value in the min heap.
  • Moreover at every insertion in the heaps, we ensure that the sizes of the two heaps differ no longer by one (for odd values) or are equal (even values).
  • If we maintain this, then for the median operation, we will have three choices:
    1. The max heap size is greater than the min heap size.
      • Then we return the front value from the max heap.
    2. The min heap size is greater than the max heap size.
      • Then we return the front value from the min heap.
    3. Both the heaps are of equal size.
      • Then we return the average of the front of the max and min heap.

๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป Solution - Priority Queue

  • Below is the code for the two pointers approach. ``` class MedianFinder { PriorityQueue pqOne, pqTwo;

    public MedianFinder() {

      pqOne = new PriorityQueue<>((a,b) -> b - a);
      pqTwo = new PriorityQueue<>();
    

    }

    public void addNum(int num) {

      pqOne.add(num);
    
    if(!pqOne.isEmpty() && !pqTwo.isEmpty() && 
       pqOne.peek() > pqTwo.peek()
      ) {
        pqTwo.add(pqOne.poll());
    }


    if(pqOne.size() > pqTwo.size() + 1) {
        pqTwo.add(pqOne.poll());
    }
    if(pqTwo.size() > pqOne.size() + 1) {
        pqOne.add(pqTwo.poll());
    }
}

public double findMedian() {
    int s1 = pqOne.size();
    int s2 = pqTwo.size();

    if(s1 > s2) {
        return (double) pqOne.peek();
    }
    else if(s2 > s1) {
        return (double) pqTwo.peek();
    }
    double first = pqOne.peek();
    double second = pqTwo.peek();

    return (first + second) / 2.0;
}

}


Time Complexity:

  • findMedian: O(1)
  • addNum = O(log n) Space Complexity: O(n) ```

You can find the link to the GitHub repo for this question here: 295. Find Median from Data Stream.


Conclusion

That's a wrap for today's problem. If you liked my explanation then please do drop a like/ comment. Also, please correct me if I've made any mistakes or if you want me to improve something!

Thank you for reading!