美文网首页
[刷题防痴呆] 0295 - 数据流的中位数 (Find Med

[刷题防痴呆] 0295 - 数据流的中位数 (Find Med

作者: 西出玉门东望长安 | 来源:发表于2022-04-26 08:49 被阅读0次

题目地址

https://leetcode.com/problems/find-median-from-data-stream/description/

题目描述

295. Find Median from Data Stream


Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

For example,
[2,3,4], the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

Design a data structure that supports the following two operations:

void addNum(int num) - Add a integer number from the data stream to the data structure.
double findMedian() - Return the median of all elements so far.
 

Example:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3) 
findMedian() -> 2
 

Follow up:

If all integer numbers from the stream are between 0 and 100, how would you optimize it?
If 99% of all integer numbers from the stream are between 0 and 100, how would you optimize it?

思路

  • 方法1, sort. O(nlogn).
  • 方法2, two heaps. 维护两个堆, maxHeap和minHeap. O(logn).

关键点

  • 这题实际上是用堆来求中位数.
  • 做法为, 开2个堆. 一个maxHeap保留中位数左边的所有数. 一个minHeap保留中位数右边的所有数.
  • for循环nums数组, 对于每一个数, 把数加到maxHeap中. 然后从maxHeap中拿出最大的扔到minHeap中. 如果这时minHeap还是比maxHeap size大, 把minHeap中最小的加到maxHeap中.
  • 这样就保证了, maxHeap要么是有当前n/2的数, 要么就有当前n/2 + 1的数.
  • 加数结束后, peek maxHeap则为当前的中位数.
  • 注意, PriorityQueue本身是最小堆. 用Collections.reverseOrder实现最大堆.

代码

  • 语言支持:Java

// 方法1, sort
class MedianFinder {

    List<Integer> list;    
    
    /** initialize your data structure here. */
    public MedianFinder() {
        list = new ArrayList<>();
    }
    
    public void addNum(int num) {
        list.add(num);
    }
    
    public double findMedian() {
        Collections.sort(list);
        
        int length = list.size();
        
        if (length % 2 == 0) {
            return (list.get(length / 2) + list.get((length / 2 - 1))) * 0.5;
        } else {
            return list.get(length / 2);
        }
    }
}

// 方法2, two heaps 左边多1个
class MedianFinder {

    PriorityQueue<Integer> minHeap;
    PriorityQueue<Integer> maxHeap;
    public MedianFinder() {
        minHeap = new PriorityQueue<>();
        maxHeap = new PriorityQueue<>((a, b) -> (b - a));
    }
    
    public void addNum(int num) {
        maxHeap.offer(num);
        minHeap.offer(maxHeap.poll());
        if (minHeap.size() > maxHeap.size()) {
            maxHeap.offer(minHeap.poll());
        }
    }
    
    public double findMedian() {
        int size = minHeap.size() + maxHeap.size();
        if (size % 2 == 0) {
            return (double) (maxHeap.peek() + minHeap.peek()) / 2;
        } else {
            return (double) maxHeap.peek();
        }
    }
}

// two heaps, 奇数时右边多1个
class MedianFinder {

    PriorityQueue<Integer> minHeap;
    PriorityQueue<Integer> maxHeap;
    public MedianFinder() {
        minHeap = new PriorityQueue<>();
        maxHeap = new PriorityQueue<>((a, b) -> (b - a));
    }
    
    public void addNum(int num) {
        if (minHeap.size() == 0 || num >= minHeap.peek()) {
            minHeap.offer(num);
        } else {
            maxHeap.offer(num);
        }
        adjust(maxHeap, minHeap);
    }
    
    public double findMedian() {
        if (maxHeap.size() == minHeap.size()) {
            return maxHeap.peek() / 2.0 + minHeap.peek() / 2.0;
        } else {
            return (double)(minHeap.peek());
        }
    }

    private void adjust(PriorityQueue<Integer> left, PriorityQueue<Integer> right) {
        while (left.size() > right.size()) {
            right.add(left.poll());
        }
        while (right.size() - left.size() > 1) {
            left.add(right.poll());
        }
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

相关文章

网友评论

      本文标题:[刷题防痴呆] 0295 - 数据流的中位数 (Find Med

      本文链接:https://www.haomeiwen.com/subject/yfdcyrtx.html