一、题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,
那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,
那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,
使用GetMedian()方法获取当前读取数据的中位数。
二、解题思路
方法一、利用list来保存读入的数据流,在利用list的sort方法排序后,再找出中位数
方法二、利用一个大顶堆和一个小顶堆,两个堆的元素数量差不能超过1,大顶堆的最大值小于小顶堆的最小值。这样,如果输入流的个数是偶数个的话,就分别取两个堆顶值再求平均值;如果是输入流是奇数个的话,就去多一个元素的那个堆的顶元素。
三、java代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
*@Desc: 数据流中的中位数
*@author: ghd
*@Date: 2018年12月19日 下午2:11:24
*/
public class Solution_64 {
/**
* 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,
* 那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,
* 那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,
* 使用GetMedian()方法获取当前读取数据的中位数。
*/
//方法一、利用list来保存读入的数据流,在利用list的sort方法排序后,再找出中位数
ArrayList<Integer> list = new ArrayList<Integer>();
public void Insert_1(Integer num) {
list.add(num);
}
//获取中位数
public Double GetMedian_1() {
double res = 0;
int size = list.size();
if(size != 0){
Integer [] integers = (Integer [])list.toArray(new Integer[size]);
Arrays.sort(integers);
if((size & 1) == 0){ //为偶数时
res = (integers[size/2-1] + integers[size/2])/2.0; //注意数组下标0开始
}else {
int temp = size/2;
res = integers[temp];
}
}
return res;
}
//方法二、利用一个大顶堆和一个小顶堆,两个堆的元素数量差不能超过1,大顶堆的最大值小于小顶堆的最小值
//这样,如果输入流的个数是偶数个的话,就分别取两个堆顶值再求平均值;如果是输入流是奇数个的话,就去多一个元素的那个堆的顶元素。
PriorityQueue<Integer> minQueue = new PriorityQueue<Integer>();
PriorityQueue<Integer> maxQueue = new PriorityQueue<Integer>(15,new Comparator<Integer>() { //15为初始元素个数,设置比较规则
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
}
);
int count = 0; //记录输入流的个数
public void Insert_2(Integer num) {
count ++;
if((count & 1) == 0){ //输入流个数为偶数时,放到minQueue里
if(!maxQueue.isEmpty() && num<maxQueue.peek()){
maxQueue.offer(num); //放入mixQueue之前,读入的num与maxQueue的最大值比较
num = maxQueue.poll();
}
minQueue.offer(num);
}else {
if(!minQueue.isEmpty() && num>minQueue.peek()){
minQueue.offer(num);
num = minQueue.poll();
}
maxQueue.offer(num);
}
}
public Double GetMedian_2() {
double res = 0;
if((count & 1) == 0){ //偶数个
res = (minQueue.peek()+maxQueue.peek())/2.0;
}else {
res = (double)maxQueue.peek();
}
return res;
}
}