LeetCode_295数据流的中位数

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
在这里插入图片描述
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-median-from-data-stream
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class MedianFinder {
    /*
    动态维护一个大顶堆 max_heap 和一个小顶堆 min_heap,
    这两个堆各自存放“一半”的数据(这里的“一半”是指两个堆的size()相差小于等于1),
    且维持 max_heap 的堆顶 <= min_heap 的堆顶。
    在插入新元素x时,如果max_heap为空,直接将x压入max_heap;
    否则,先比较 max_heap.size() 与 min_heap.size():
        若max_heap与min_heap元素个数相同:
            若 x < max_heap 的堆顶,将x压入 max_heap;
            否则,将x压入 min_heap;
        若 max_heap 比 min_heap 的size小(需要通过调整两个堆,以保证平衡):
            若 x < max_heap 的堆顶,直接将x压入 max_heap;
            否则,为了总是保持min_heap>=max_heap,先将x压入min_heap, 再将 min_heap 的堆顶弹出并压入 max_heap
       若 max_heap 比 min_heap 的size大(同样需要通过调整两个堆):
            若 x > max_heap 的堆顶,直接将x压入 min_heap;
            否则,为了总是保持min_heap>=max_heap,先将x压入max_heap, 再将max_heap 的堆顶弹出并压入 min_heap
    */

    //先创建大顶堆与小顶堆
    int SIZE = 20000;
    int[] maxHeap = null;
    int[] minHeap = null;
    int len1 = 0;
    int len2 = 0;

    /** initialize your data structure here. */
    public MedianFinder() {
        maxHeap = new int[SIZE];
        minHeap = new int[SIZE];
    }
    
    public void addNum(int num) {
        if(len1==0){
            maxHeap[len1++] = num;
        }else{
            if(len1==len2){
                if(num<maxHeap[0]){
                    addMaxHeapNum(maxHeap,num);
                }else{
                    addMinHeapNum(minHeap,num);
                }
            }else if(len1<len2){
                if(num<maxHeap[0]){
                    addMaxHeapNum(maxHeap,num);
                }else{
                    addMinHeapNum(minHeap,num);
                    addMaxHeapNum(maxHeap,minHeap[0]);
                    swap(minHeap,0,len2-1);
                    len2--;
                    adjustMin(minHeap,0,len2);
                }
            }else{
                if(num>maxHeap[0]){
                    addMinHeapNum(minHeap,num);
                }else{
                    addMaxHeapNum(maxHeap,num);
                    addMinHeapNum(minHeap,maxHeap[0]);
                    swap(maxHeap,0,len1-1);
                    len1--;
                    adjustMax(maxHeap,0,len1);
                }
            }
        }
    }

    public double findMedian() {
        if(len1<len2){
            return minHeap[0];
        }else if(len1==len2){
            return (maxHeap[0]+minHeap[0])/2.0;
        }else{
            return maxHeap[0];
        }
    }

    //将数据加入大顶堆中
    private void addMaxHeapNum(int[] maxHeap, int num){
        maxHeap[len1++] = num;
        for(int i=len1/2;i>=0;i--){
            adjustMax(maxHeap,i,len1);
        }
    }

    //将数据加入小顶堆中
    private void addMinHeapNum(int[] minHeap, int num){
        minHeap[len2++] = num;
        for(int i=len2/2;i>=0;i--){
            adjustMin(minHeap,i,len2);
        }
    }

    // 调整大顶堆
    private void adjustMax(int[] nums, int i, int len){
        int left = i*2+1;
        int right = i*2+2;
        int max = i;
        if(left<len && nums[max]<nums[left]){
            max = left;
        }
        if(right<len && nums[max]<nums[right]){
            max = right;
        }
        if(max!=i){
            swap(nums,i,max);
            adjustMax(nums,max,len);
        }
    }

    //调整小顶堆
    private void adjustMin(int[] nums, int i, int len){
        int left = i*2+1;
        int right = i*2+2;
        int min = i;
        if(left<len && nums[min]>nums[left]){
            min = left;
        }
        if(right<len && nums[min]>nums[right]){
            min = right;
        }
        if(min!=i){
            swap(nums,i,min);
            adjustMin(nums,min,len);
        }
    }

    private void swap(int[] nums, int i, int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */
发布了250 篇原创文章 · 获赞 0 · 访问量 1257

猜你喜欢

转载自blog.csdn.net/qq_36198826/article/details/103923497
今日推荐