贵州网站建设设计公司,程序员用来做笔记的网站,西宁做腋臭北大网站l,海口市龙华区核酸检测题目描述
中位数是有序整数列表中的中间值。如果列表的大小是偶数#xff0c;则没有中间值#xff0c;中位数是两个中间值的平均值。
例如 arr [2,3,4] 的中位数是 3 。例如 arr [2,3] 的中位数是 (2 3) / 2 2.5 。
实现 MedianFinder 类: MedianFinder() 初始化 Media…题目描述
中位数是有序整数列表中的中间值。如果列表的大小是偶数则没有中间值中位数是两个中间值的平均值。
例如 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 之前存在如下的大小关系
当数据流元素数量为偶数l 和 r 大小相同此时动态中位数为两者堆顶元素的平均值当数据流元素数量为奇数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 {//大顶堆PriorityQueueInteger l new PriorityQueue((a,b)-b-a);//小顶堆(默认)PriorityQueueInteger 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();}}
}