题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数
 
 直接排序:
class Solution {
    vector<int> numbers;
public:
    void Insert(int num)
    {
        numbers.push_back(num);
        sort(numbers.begin(),numbers.end());
    }

    double GetMedian()
    { 
        
        int len = numbers.size();
        if(len %2 == 0)
            return (numbers[len/2-1]+numbers[len/2])/2.0;
        else
            return numbers[len/2];
    }

};

 

使用一个大顶堆和一个小顶堆来完成:

class Solution {
    priority_queue<int,vector<int>,greater<int> > smallCap;
    priority_queue<int,vector<int>,less<int> > bigCap;
public:
    void Insert(int num)
    {
        if(smallCap.size() == 0 && bigCap.size() == 0)
            smallCap.push(num);
        else if(smallCap.size()==bigCap.size()){
            if(num<smallCap.top())
                bigCap.push(num);
            else
                smallCap.push(num);
        }else if(smallCap.size()-bigCap.size() == 1){
            
            if(num<smallCap.top())
                bigCap.push(num);
            else{
                bigCap.push(smallCap.top());
                smallCap.pop();
                smallCap.push(num);
            }
        }else if(smallCap.size()-bigCap.size() == -1){
            if(num<smallCap.top()&&num<bigCap.top()){
                smallCap.push(bigCap.top());
                bigCap.pop();
                bigCap.push(num);
            }
            else{
                smallCap.push(num);
            }
        }else{
            return;
        }
    }

    double GetMedian()
    { 
        if(smallCap.size() == bigCap.size()){
            return (smallCap.top() + bigCap.top())/2.0;
        }else if(smallCap.size()-bigCap.size() == 1){
            return smallCap.top();
        }else{
            return bigCap.top();
        }
    }

};

 使用堆的方式可以达到插入为O(logn),取中位数为O(1)的时间复杂度

java实现的更加简洁的写法:

import java.util.*;
public class Solution {
    
    public Comparator<Integer> cmp = new Comparator<Integer>() {
        public int compare(Integer e1,Integer e2){
            return e2 - e1;
        }
    };
    private PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    private PriorityQueue<Integer> maxHeap = new PriorityQueue<>(cmp);
    int count = 0;
    public void Insert(Integer num) {
        
        if((count & 1) == 0){//偶数个,先插入大顶堆,再弹出大顶堆最大元素放入小顶堆
            maxHeap.offer(num);
            minHeap.offer(maxHeap.poll());
        }else{//奇数个,先插入小顶堆,再弹出小顶堆最小元素放入大顶堆
            minHeap.offer(num);
            maxHeap.offer(minHeap.poll());
        }
        count++;
    }

    public Double GetMedian() {
        if((count & 1) == 1)
            return minHeap.peek().doubleValue();
        else
            return (minHeap.peek()+maxHeap.peek())/2.0;
    }


}

 

class MedianFinder {
    PriorityQueue<Integer> lo;//存小元素的大顶堆
    PriorityQueue<Integer> hi;//存较大元素的小顶堆
    /** initialize your data structure here. */
    public MedianFinder() {
        lo = new PriorityQueue<>((x,y)->y-x);
        hi = new PriorityQueue<>();
    }
    
    public void addNum(int num) {
        lo.offer(num);
        hi.offer(lo.peek());
        lo.poll();
        if(lo.size()<hi.size()){
            lo.offer(hi.peek());
            hi.poll();
        }
    }
    
    public double findMedian() {
        return lo.size()>hi.size()?lo.peek():0.5*(lo.peek()+hi.peek());
    }
}

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

 

posted on 2020-10-24 22:02  曹婷婷  阅读(89)  评论(0)    收藏  举报