暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

数据结构和算法【99】数据流中的中位数

皮皮克克 2023-12-21
64

点击关注公众号,干货第一时间送达


做过实时数仓的小伙伴,

应该都知道什么是数据流。

当然,熟悉Kafka的仁兄们,

对此也不陌生。

数据流,讲究的就是一个变化。

今天咱们看一道 "困难" 的题目,

来自力扣:

原题链接:

https://leetcode.cn/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof/description/


一、屏幕前的吴彦祖和刘亦菲们,请听题


需要实现的是一种数据结构,

能够完成对数据流的中位数,准确抓取。

该结构如下:

class MedianFinder {

    public MedianFinder() {

    }
    
    public void addNum(int num) {

    }
    
    public double findMedian() {

    }
}


嘶嘶嘶。。。

说实话,

是不是有点棘手?

且看小编娓娓道来。


二、解题

中位数,处于一组有序数字的中间位置。

如果我们能够把一串数字,

较小部分用大根堆存储,较大部分用小根堆存储,

那么大根堆对顶,就是较小部分最大的元素,

小根堆堆定,就是较大部分最小的元素,

那么,中位数就好求了。

举个例子:


当3流入时,判断3和大根堆堆顶大小,3 < 5,则3进入大根堆:

同时,需要判断两个堆size大小关系,

如果差值超过1,则进行调整:


于是:


继续流入6,判断 6 >3,则6进入小根堆:


接下来7,7 >3,也进入小根堆:


记得判断两个堆size大小,此时需要调整了:

数据流停止了,

如果两个堆size一样,则中位数就是两个堆顶的平均数:(5+6)/2

如果size不一样,取size较大的那个堆堆顶即可。

此方法是不是很简单

看看代码。



完整代码:

public class CodingDemo_03 {

    /**
     * 数据流中的中位数
     */

    class MedianFinder {

        //大根堆
        PriorityQueue<Integer> maxHeap;
        //小根堆
        PriorityQueue<Integer> minHeap;

        //初始化堆
        public MedianFinder() {
            maxHeap = new PriorityQueue<>(new MaxHeapComparator());
            minHeap = new PriorityQueue<>(new MinHeapComparator());
        }

        //添加新数字
        public void addNum(int num) {
            //1,优先加入大根堆,
            //每次加入,都调整两个堆,保持堆size差小于等于1
            if (maxHeap.isEmpty() || num <= maxHeap.peek()){
                maxHeap.offer(num);
            } else {
                minHeap.offer(num);
            }
            modifyTwoHeap();
        }

        //调整两个堆
        public void modifyTwoHeap(){
            if (maxHeap.size() == minHeap.size() + 2){
                minHeap.offer(maxHeap.poll());
            }
            if (minHeap.size() == maxHeap.size() + 2){
                maxHeap.offer(minHeap.poll());
            }
        }

        //查找中位数
        public double findMedian() {
            if (maxHeap.isEmpty()){
                return -1;
            }

            if (maxHeap.size() == minHeap.size()){
                return (double) (maxHeap.peek() + minHeap.peek())/2;
            } else {
                return maxHeap.size() > minHeap.size() ? maxHeap.peek() : minHeap.peek();
            }
        }
    }


    //自定义大根堆比较器,正序排列
    class MaxHeapComparator implements Comparator<Integer>{

        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    }

    //自定义小根堆比较器,逆序排列
    class MinHeapComparator implements Comparator<Integer>{

        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 - o2;
        }
    }
}


去力扣试试:



结束语:
Ok,就是本篇文章的全部内容了。
如果各位有不懂的地方,欢迎发消息给小编,小编会进行详细地解答。
最后,请屏幕前的各位吴彦祖和刘亦菲们,动动你们的小手,给小编一个

文章转载自皮皮克克,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论