从零学算法295

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

例如 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

  • 他人解法:直接两个优先队列开始表演魔法(我这辈子估计也想不出这解法)。首先定义两个堆,各存放列表中一半的数据,小顶堆 A 存放较大部分,大顶堆 B 存放较小部分,优先往小顶堆存放元素(即,列表元素个数为奇数时,A 多存一个)。首先根据这个定义,当元素个数为奇数个时,我们就应该从 A 中取中位数,因为 A 多存的那个数就是中位数,为了让 A 堆顶元素就是中位数,我们就需要让 A 保持升序。当元素个数为偶数个,我们需要从 A,B 的堆顶各自取出一个数然后求平均数,那么 B 的堆顶如果需要是第二大的中位数,那 B 就需要保持降序。定义堆与取中位数已经解决了,剩下的 addNum 可以说是神来之笔。当 A B 元素个数不相同时,那么就该向 B 添加数了,但是为此时并不是直接添加到 B,因为我不确定我直接添加以后还能否保持(A 存放较大部分,B 存放较小部分)这个特性。所以我先把他加到 A,因为 A 是升序存储,所以堆顶的元素一直是最小的,把添加的数加到 A 以后再弹出堆顶的数给 B,那么此时弹出的数一定是小于 A 中此时所有的数的了,也就是说,我保持了 A 中的都是较大数。同理,当 AB 元素个数相同时,我要先给 A 加元素,但我先往 B 中添加,由于 B 是降序优先队列,所以 B 的堆顶元素是 B 的最大元素,我把 B 的堆顶元素弹出给 A,我就保证了 B 的所有数都小于弹给 A 的数。这样一来,我就保证了 A 只存放较大部分的数,B 只存放较小部分的数。
  • 或者说一个数被添加时,先看看是加给谁,如果是 A 中多了一个名额,因为 A 只收强者,所以它就需要先打败 B 中的所有数证明自己,否则只能把这个新的名额给 B 中此时的最强者了。而如果 B 中多了一个名额,他当然不想去弱者队,它就先去 A 中看看有没有它能打败的,有的话就把 A 中此时最弱者挤到了 B,否则只能它进 B 了。
java 复制代码
  // 小顶堆,存放较大部分
  public Queue<Integer> A = new PriorityQueue<>();
  // 大顶堆,存放较小部分
  public Queue<Integer> B = new PriorityQueue<>((x,y)->y-x);
  /** initialize your data structure here. */
  public MedianFinder() {

  }
  
  public void addNum(int num) {
      if(A.size() != B.size()) {
      	// B 有新名额了,先去 A 中挑战一下
          A.add(num);
          // 最后有没有留在 A 我就不知道了,但是 A 中此时最弱的要去 B 的新名额了
          B.add(A.poll());
      } else {
      	// A 有新名额了,先去 B 中证明自己是 B 中最强的
          B.add(num);
          // 最后有没有进 A 我也不知道,但是一定是 B 中最强者进 A 的新名额了
          A.add(B.poll());
      }
  }
  
  public double findMedian() {
      return A.size() != B.size() ? A.peek() : (A.peek() + B.peek()) / 2.0;
  }
相关推荐
P.H. Infinity几秒前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天4 分钟前
java的threadlocal为何内存泄漏
java
sp_fyf_20249 分钟前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘
caridle15 分钟前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^21 分钟前
数据库连接池的创建
java·开发语言·数据库
苹果醋324 分钟前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花29 分钟前
【JAVA基础】Java集合基础
java·开发语言·windows
香菜大丸29 分钟前
链表的归并排序
数据结构·算法·链表
jrrz082829 分钟前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
小松学前端32 分钟前
第六章 7.0 LinkList
java·开发语言·网络