LeetCode_Heap_295. Find Median from Data Stream 数据流的中位数 【堆,中位数】【C++/java】【困难】

目录

一,题目描述

英文描述

中文描述

示例与说明

二,解题思路

三,AC代码

C++

Java

四,解题过程

第一博


一,题目描述

英文描述

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

  • For example, for arr = [2,3,4], the median is 3.
  • For example, for arr = [2,3], the median is (2 + 3) / 2 = 2.5.

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.

中文描述

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

例如,

[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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二,解题思路

当数组为有序数组时,就可以直接根据数量关系判断中位数了,有没有很方便的管理顺序性和数量关系的数据结构呢?

当然有了,那就是堆。

数量关系:

  • 假设数组有序,设计一个大根堆,一个小根堆。大根堆存放有序数组中前 n/2 或者 n/2+1 个元素,小根堆存放剩下的即可(大小根堆的堆顶是最中间的元素)。这样当大小根堆数量相等时,中位数即两个堆堆顶元素的平均值。大根堆数量比小根堆多一时,中位数即大根堆堆顶。

有序性:

只需要保证大根堆的堆顶永远小于小根堆的堆顶即可。当新增一个元素num时,先判断大根堆小根堆的数量关系:

  • 若大根堆元素数量比小根堆多一,则表明需要有一个元素被添加到小根堆了,至于是将大根堆堆顶还是num添加到小根堆中,就需要比较他们的大小关系,再做判断;
  • 若大根堆元素数量与小根堆相等,则表明需要有一个元素被添加到大根堆了,至于是将小根堆堆顶还是num添加到大根堆中,就需要比较他们的大小关系,再做判断;

三,AC代码

C++

class MedianFinder {
public:
    priority_queue<int, vector<int>, less<int>> bigHeap;
    priority_queue<int, vector<int>, greater<int>> smallHeap;
    MedianFinder() {

    }
    
    void addNum(int num) {
        if (bigHeap.size() - smallHeap.size() == 0) {
            if (smallHeap.size() == 0 || num < smallHeap.top()) {
                bigHeap.push(num);
            } else {
                smallHeap.push(num);
                bigHeap.push(smallHeap.top());
                smallHeap.pop();
            }
        } else if (bigHeap.size() - smallHeap.size() == 1) {
            if (num > bigHeap.top()) {
                smallHeap.push(num);
            } else {
                bigHeap.push(num);
                smallHeap.push(bigHeap.top());
                bigHeap.pop();
            }
        }
    }
    
    double findMedian() {
        if (bigHeap.size() == smallHeap.size()) {
            return ((double)bigHeap.top() + smallHeap.top()) / 2;
        } else {
            return (double)bigHeap.top();
        }
    }
};

Java

class MedianFinder {
    // 假设将整个递增数组分为两部分,前半部分为大根堆,后半部分为小根堆
    // 只要维护好大小根堆的数量关系,就可以快速定位中位数了
    PriorityQueue<Integer> bigHeap, smallHeap;
    public MedianFinder() {
        bigHeap = new PriorityQueue<>((a, b) -> (b - a));
        smallHeap = new PriorityQueue<>((a, b) -> (a - b));
    }
    
    public void addNum(int num) {
        
        if (bigHeap.size() - smallHeap.size() == 0) {
            if (smallHeap.size() == 0 || num < smallHeap.peek()) {
                // 小根堆为空或者num小于小根堆的堆顶,则将num添加到大根堆中
                bigHeap.offer(num);
            } else {
                // 小根堆不为空,且小根堆的堆顶元素小于num,则将小根堆堆顶移到大根堆中,num则插入到小根堆中,保证从小到大的顺序性
                smallHeap.offer(num);
                bigHeap.offer(smallHeap.peek());
                smallHeap.poll();
            }
        } else if (bigHeap.size() - smallHeap.size() == 1) {
            if (num > bigHeap.peek()) {
                // num大于大根堆堆顶,直接将num加入到小根堆中
                smallHeap.offer(num);
            } else {
                // 将num加入到大根堆中,并将大根堆堆顶元素移到小根堆中
                bigHeap.offer(num);
                smallHeap.offer(bigHeap.peek());
                bigHeap.poll();
            }
        }
    }
    
    public double findMedian() {
        if (bigHeap.size() == smallHeap.size()) {
            return ((double)bigHeap.peek() + (double)smallHeap.peek()) / 2;
        } else {
            return (double)bigHeap.peek();
        }
    }
}

四,解题过程

第一博

刚开始没搞清楚大根堆小根堆元素转移的方法,直接根据数量关系添加元素了,调了好长时间。。。

一定要记得:不仅要维持数量关系,还要维持顺序性(这里采用从小到大的顺序)

 

猜你喜欢

转载自blog.csdn.net/qq_41528502/article/details/121197667
今日推荐