LeetCode295之数据流的中位数(相关话题:优先队列)
创始人
2024-05-30 12:47:34
0

题目描述

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。

  • 例如 arr = [2,3,4] 的中位数是 3 。
  • 例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5 。

实现 MedianFinder 类:

  • MedianFinder() 初始化 MedianFinder 对象。

  • void addNum(int num) 将数据流中的整数 num 添加到数据结构中。

  • double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。

示例 1:

输入
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
输出
[null, null, null, 1.5, null, 2.0]解释
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1);    // arr = [1]
medianFinder.addNum(2);    // arr = [1, 2]
medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)
medianFinder.addNum(3);    // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0

提示:

  • -105 <= num <= 105
  • 在调用 findMedian 之前,数据结构中至少有一个元素
  • 最多 5 * 104 次调用 addNum 和 findMedian

思路分析

一开始没看懂题目,以为只要用List存储数据,取中位数即可,认真审题可以发现,中位数是有序整数列表中的中间值,所以必须对插入的数据先排序才能求中位值

在数据流中,数据会不断涌入结构中,那么也就面临着需要多次动态调整以获得中位数。 因此实现的数据结构需要既需要快速找到中位数,也需要做到快速调整。

首先能想到就是二叉搜索树,在平衡状态下,树顶必定是中间数,然后再根据长度的奇偶性决定是否取两个数。

此方法效率高,但是手动编写较费时费力。

根据只需获得中间数的想法,可以将数据分为左右两边,一边以最大堆的形式实现,可以快速获得左侧最大数, 另一边则以最小堆的形式实现。其中需要注意的一点就是左右侧数据的长度差不能超过1。 这种实现方式的效率与AVL平衡二叉搜索树的效率相近,但编写更快

显然,为了可以在 O(1) 的复杂度内取得当前中位数,我们应当令 l 为大根堆,r 为小根堆,并人为固定 l 和 r 之前存在如下的大小关系:

  1. 当数据流元素数量为偶数:l 和 r 大小相同,此时动态中位数为两者堆顶元素的平均值;
  2. 当数据流元素数量为奇数:l 比 r 多一,此时动态中位数为 l 的堆顶原数。

为了满足上述说的奇偶性堆大小关系,在进行 addNum 时,我们应当分情况处理:

插入前两者大小相同,说明插入前数据流元素个数为偶数,插入后变为奇数。我们期望操作完达到「l 的数量为 r 多一,同时双堆维持有序」,进一步分情况讨论:

  • 如果 r 为空,说明当前插入的是首个元素,直接添加到 l 即可;
  • 如果 r 不为空,且 num <= r.peek(),说明 num 的插入位置不会在后半部分(不会在 r 中),直接加到 l 即可;
  • 如果 r 不为空,且 num > r.peek(),说明 num 的插入位置在后半部分,此时将 r 的堆顶元素放到 l 中,再把 num 放到 r(相当于从 r 中置换一位出来放到 l 中)。

插入前两者大小不同,说明前数据流元素个数为奇数,插入后变为偶数。我们期望操作完达到「l 和 r 数量相等,同时双堆维持有序」,进一步分情况讨论(此时 l 必然比 r 元素多一):

  • 如果 num >= l.peek(),说明 num 的插入位置不会在前半部分(不会在 l 中),直接添加到 r 即可。
  • 如果 num < l.peek(),说明 num 的插入位置在前半部分,此时将 l 的堆顶元素放到 r 中,再把 num 放入 l 中(相等于从 l 中替换一位出来当到 r 中)。

 代码实现

class MedianFinder {//大顶堆PriorityQueue l = new PriorityQueue<>((a,b)->b-a);//小顶堆(默认)PriorityQueue r = new PriorityQueue<>((a,b)->a-b);public void addNum(int num) {int s1 = l.size(), s2 = r.size();if (s1 == s2) {if (r.isEmpty() || num <= r.peek()) {l.add(num);} else {l.add(r.poll());r.add(num);}} else {if (l.peek() <= num) {r.add(num);} else {r.add(l.poll());l.add(num);}}}public double findMedian() {int s1 = l.size(), s2 = r.size();if (s1 == s2) {return (l.peek() + r.peek()) / 2.0;} else {return l.peek();}}
}

相关内容

热门资讯

梦到在上课 梦到在上课老师你也敢戏弄?别说给小鞋你穿,紧紧鞋带都够你受的。这是你潜意识里发泄心理压力,而达到心理...
怎么写一个人很温柔,写一段话 怎么写一个人很温柔,写一段话我不知道那些鸿雁究竟是怎样掠夺了我忧郁无助的天空。就像你撩动温柔浸渍了我...
中风了应该怎样处理? 中风了应该怎样处理?中风多由脑血管疾病引发,是一种常见急症。处理原则是:保持病人安静,让病人卧下,将...
盘点2021高评分的古装剧,哪... 盘点2021高评分的古装剧,哪部剧最让你感到意难平?杨幂的斛珠夫人 。在这部剧的结局当中,男一男二,...
奔字的笔顺笔画顺序 奔字的笔顺笔画顺序汉字: 奔 读音: bèn bēn 部首: 大 笔画...
智商跟性格有关吗 智商跟性格有关吗有关啊,有相关的研究,但是相关未必是因果,可能是因为智力高所以才有的那些性格或者别的...
魏书生在学生眼中是个怎样的老师... 魏书生在学生眼中是个怎样的老师?魏书生的学生对他真实评价如下:1、作为当代教育大家,魏书生魏老师,在...
太平人寿卓越世享五年交费最低是... 太平人寿卓越世享五年交费最低是多少您好,目前公司已经停售1年,3年,5年交的卓越世享,但可以10年交...
【活动策划】遇良师结益友乐一生 【活动策划】遇良师结益友乐一生唐代文学家韩愈曾说:“古之学者必有师。”爱因斯坦也说:“世间最美好的东...
压死猫预兆什么意思 压死猫预兆什么意思1、压死猫是一种不祥的征兆在中国古代文化中,猫被认为是吉祥之物,它们可以驱鬼辟邪。...
男主小时候被灭门,长大后复仇? 男主小时候被灭门,长大后复仇?男主小时候躲在箱子里,亲眼看见父亲被杀,失忆了事后躲过一劫,被收养了,...
什么是交心? 什么是交心?什么是交心?烦恼... 什么是交心?烦恼 展开 要别人和自己交心,成为好友。首先,...
一个讲叛逆男孩的电影 一个讲叛逆男孩的电影经典教育片《少年犯》,周星驰喜剧片《武状元苏乞儿》,还有一个讲女孩的(虽然不是男...
麒麟真的存在吗?那张黑白的麒麟... 麒麟真的存在吗?那张黑白的麒麟照片是谁拍的?   麒麟是我国从古至今...
求推荐以爱情为主线的男频小说 求推荐以爱情为主线的男频小说微微一笑很倾城。。。。。。。。
华尔兹开头的电影叫什么 华尔兹开头的电影叫什么《爱乐之城》。根据查询新浪微博信息显示,电影《爱乐之城》选用了华尔兹音乐作为开...
农夫与蛇的故事讲了什么道理 农夫与蛇的故事讲了什么道理农夫与蛇的故事的道理是:做人一定要分清善恶,只能把援助之手伸向善良的人。对...
请问这对八寸音箱属于舞台的还是... 请问这对八寸音箱属于舞台的还是落地的?适合家用吗?  正面回答:可以家用,但毫无性价比可言。舞台音箱...
求书名:古言小说的女配叫柳琉璃... 求书名:古言小说的女配叫柳琉璃,男配叫萧天逸,男主是不受宠的王爷,好像是穿越小说,女主开始在树上。好...
雪山飞狐到底写到哪?哪有全本的 雪山飞狐到底写到哪?哪有全本的有两部关于胡斐的小说《雪山飞狐》和《飞狐外传》。《飞狐外传》是《雪山飞...