题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
解题思路—直接插入:使用ArrayList,每次输入数据时,使用直接插入的思想,将数据按顺序插入list中。
但是对于海量数据而言,直接插入法效率太低,所以推荐使用大顶堆小顶堆来解这道题,将数据尽量平均的存入大顶堆和小顶堆中,堆顶即为中位数。
✨解题思路—大顶堆小顶堆-效率较高版:去除不必要的插入
规定:0<=小顶堆数据个数-大顶堆数据个数<=1
// minheap:小顶堆;maxheap:大顶堆。
// top_minheap:小顶堆的堆顶元素;top_maxheap:大顶堆的堆顶元素。
1.当堆中数据总数为奇数时(小顶堆个数比大顶堆多一个)
当num<=top_minheap,将insert的数据num直接放入大顶堆;
当num>top_minheap,先将top_minheap加入maxheap,再将num加入minheap中。
此时,堆中数据个数变为偶数,中位数输出:(top_minheap+top_maxheap)/2
2.当堆中数据总数为偶数时(小顶堆大顶堆个数一致)
当num>=top_maxheap,将insert的数据num直接放入小顶堆;
当num<top_maxheap,先将top_maxheap加入minheap,再将num加入maxheap中。
此时,堆中数据个数变为奇数,最后中位数输出:top_minheap
解题思路—大顶堆小顶堆-效率较低版:无需判断插入数值大小,但是插入次数变多
规定:0<=小顶堆数据个数-大顶堆数据个数<=1
1.当堆中数据总数为奇数时(小顶堆个数比大顶堆多一个)
将insert的数据num直接放入minheap中,然后将top_minheap放入maxheap中。
此时,堆中数据个数变为偶数,中位数输出:(top_minheap+top_maxheap)/2
2.当堆中数据总数为偶数时(小顶堆大顶堆个数一致)
将insert的数据num直接放入maxheap中,然后将top_maxheap放入minheap中。
此时,堆中数据个数变为奇数,最后中位数输出:top_minheap
还有一个思路:构建一棵"平衡二叉搜索树 ",各位大佬可以自己再试试。
Java解题—直接插入
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> list = new ArrayList<>();
public void Insert(Integer num) {
for(int i=list.size()-1;i>=0;i--)
if(list.get(i)<num){
list.add(i+1, num);
return;
}
list.add(0, num);
}
public Double GetMedian() {
if(list.size()==0)
return 0.0;
else if(list.size()%2==0)
return (list.get(list.size()/2)+list.get(list.size()/2-1))/2.0;
else
return (double) list.get(list.size()/2);
}
}
Java解题—大顶堆小顶堆-效率较高版
import java.util.PriorityQueue;
public class Solution {
// 定义大顶堆,使用lambda表达式
public PriorityQueue<Integer> maxheap = new PriorityQueue<>((x,y)-> y-x);
// 定义小顶堆,PriorityQueue默认创建小顶堆
public PriorityQueue<Integer> minheap = new PriorityQueue<>();
// 是否为奇数
public boolean isOdd = false;
public void Insert(Integer num) {
if(!isOdd){ // 堆中数据偶数个
if(minheap.isEmpty())
minheap.add(num);
else{
if(num>=maxheap.peek())
minheap.add(num);
else{
minheap.add(maxheap.poll());
maxheap.add(num);
}
}
}else{ // 堆中数据奇数个
if(num<=minheap.peek())
maxheap.add(num);
else{
maxheap.add(minheap.poll());
minheap.add(num);
}
}
isOdd = !isOdd;
}
public Double GetMedian() {
if(minheap.isEmpty())
return 0.0;
if(isOdd)
return (double) minheap.peek();
else
return (double) (minheap.peek()+maxheap.peek())/2;
}
}
Java解题—大顶堆小顶堆-效率较低版
import java.util.PriorityQueue;
public class Solution {
// 定义大顶堆,使用lambda表达式
public PriorityQueue<Integer> maxheap = new PriorityQueue<>((x,y)-> y-x);
// 定义小顶堆,PriorityQueue默认创建小顶堆
public PriorityQueue<Integer> minheap = new PriorityQueue<>();
// 是否为奇数
public boolean isOdd = false;
public void Insert(Integer num) {
if(!isOdd){ // 堆中数据偶数个
maxheap.add(num);
minheap.add(maxheap.poll());
}else{ // 堆中数据奇数个
minheap.add(num);
maxheap.add(minheap.poll());
}
isOdd = !isOdd;
}
public Double GetMedian() {
if(minheap.isEmpty())
return 0.0;
if(isOdd)
return (double) minheap.peek();
else
return (double) (minheap.peek()+maxheap.peek())/2;
}
}