如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
数据范围:数据流中数个数满足
,大小满足 
进阶: 空间复杂度
, 时间复杂度 %20%5C)
进阶: 空间复杂度
[5,2,3,4,1,6,7,0,8]
"5.00 3.50 3.00 3.50 3.00 3.50 4.00 3.50 4.00 "
数据流里面不断吐出的是5,2,3...,则得到的平均数分别为5,(5+2)/2,3...
[1,1,1]
"1.00 1.00 1.00 "
import java.util.*; public class Solution { public PriorityQueue<Integer> stream = new PriorityQueue<>(); public void Insert(Integer num) { stream.add(num); } public Double GetMedian() { // 1.将公共堆复制到临时堆 PriorityQueue<Integer> temp = new PriorityQueue<>(stream); // 2.计算堆的size与奇偶 int size = temp.size(); if (size == 0) { return 0.0; } int count = size / 2; if (size % 2 == 0) { count--; } // 3.依次从堆中弹出元素,找到或计算出中位数 double cur = 0.0; while (count-- >= 0) { cur = temp.poll(); } if (size % 2 == 0) { cur = (cur + temp.poll()) / 2; } return cur; } }
public class Solution { ArrayList<Integer> list = new ArrayList<>(); int median=0; public void Insert(Integer num) { int s =0,e=list.size()-1; while(s<=e){ int m = (s+e)/2; if(num < list.get(m)){ e = m-1; }else{ s = m+1; } } list.add(s,num); } public Double GetMedian() { System.out.println(list); if(list.size() % 2 == 1){ return list.get(list.size()/2) * 1.0; }else{ return (list.get(list.size()/2) + list.get(list.size()/2-1))/2.0; } } }
import java.util.*; public class Solution { ArrayList<Integer> nums = new ArrayList<>(); public void Insert(Integer num) { nums.add(num); nums.sort((a, b)-> a - b); } public Double GetMedian() { int n = nums.size(); if (n % 2 != 0) { return (double) nums.get(n / 2); } else { return (nums.get(n / 2 - 1) + nums.get(n / 2)) / 2.0; } } }
PriorityQueue<Integer> max=new PriorityQueue<>(); PriorityQueue<Integer> min=new PriorityQueue<>((m,n)->n-m); boolean flag=true; // 大根堆存放小数,且多一个,如果为奇数直接取出即可 public void Insert(Integer num) { if(flag){ min.add(num); max.add(min.poll()); }else{ max.add(num); min.add(max.poll()); } flag=!flag; } public Double GetMedian() { if(max.isEmpty()){ return 0.0; }else if(!flag){ return max.peek()*1.0; }else{ return (max.peek()+min.peek())*1.0/2; } }
public class Solution { //小堆存放较大的数据 PriorityQueue<Integer> heapMin = new PriorityQueue<>(); //大堆存放较小的数据 PriorityQueue<Integer> heapMax = new PriorityQueue<>(new Comparator<Integer>() { public int compare(Integer o1, Integer o2) { return o2 - o1; } }); public void Insert(Integer num) { if (heapMin.size() == heapMax.size()) { if (heapMin.peek() != null && num > heapMin.peek()) { heapMax.offer(heapMin.poll()); heapMin.offer(num); } else { heapMax.offer(num); } } else { if (num < heapMax.peek()) { heapMin.offer(heapMax.poll()); heapMax.offer(num); } else { heapMin.offer(num); } } } public Double GetMedian() { if (heapMax.size() == heapMin.size()) { return (heapMax.peek() + heapMin.peek()) / 2.0; } return heapMax.peek() * 1.0; } }
import java.util.*; public class Solution { List<Integer> list = new ArrayList<>(); public void Insert(Integer num) { int index = getIndex(num); list.add(index, num); } public Double GetMedian() { int size = list.size(); if(size % 2 == 0){ int num1 = list.get(size / 2 - 1); int num2 = list.get(size / 2); return 1.0 * (num1 + num2) / 2; }else{ return 1.0 * list.get(size / 2); } } // 二分,得到要插入的位置 public int getIndex(int num){ int l = 0; int r = list.size() - 1; int mid = 0; while(l <= r){ mid = l + (r - l) / 2; if(list.get(mid) >= num){ r = mid - 1; }else{ l = mid + 1; } } return l; } }
import java.util.*; public class Solution { PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(); PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(new Comparator<Integer>(){ @Override public int compare(Integer o1,Integer o2){ return o2.compareTo(o1); } }); public void Insert(Integer num) { minHeap.offer(num); maxHeap.offer(minHeap.poll()); if(minHeap.size()<maxHeap.size()){ minHeap.offer(maxHeap.poll()); } } public Double GetMedian() { if(minHeap.size()>maxHeap.size()){ return (double)minHeap.peek(); }else{ return (double )(minHeap.peek()+maxHeap.peek())/2.0; } } }
public class Solution { //堆排序的优先队列 //大根堆用于升序排序(所以求最小的前k个数用大根堆),小根堆用于降序排序(所以求最大的前k个数 //用优先队列PriorityQueue 配置大顶堆、小顶堆 //数组不断增长,每增长一位就排序一次,所以在数据增长时将其有序化 //中位数,对所有数值排序后,取两个数的平均值 //中位数:中间数字或中间两个数字的均值 //也就是说,中位数是较小的一半元素中最大的,并且也是较大的一半元素中最小的 //通过大根堆得到较小的一半元素中最大的;小根堆得到较小的一半元素中最小的 //如果是偶数,那就取两个顶顶/2;如果是奇数,那就直接返回任意一个顶。 PriorityQueue<Integer> max=new PriorityQueue<>();//小顶堆,堆顶最小 PriorityQueue<Integer> min=new PriorityQueue<>((o1,o2)->o2.compareTo(o1));//大根堆,堆顶最大 public void Insert(Integer num) {//Insert()读数据流 min.offer(num);//先加入较小的 max.offer(min.poll());//将较小部分的最大值取出(删掉),给较大的部分 if(min.size()<max.size()){ //平衡两个堆的数量 min.offer(max.poll()); } } public Double GetMedian() {//得数据的中位数 if(min.size()>max.size()){//奇数个 return (double) min.peek(); }else{//偶数个 return (double) (min.peek()+max.peek())/2.0; } }
import java.util.*; import java.math.BigDecimal; public class Solution { private ArrayList<Integer> list = new ArrayList<Integer>(); public void Insert(Integer num) { list.add(num); } public Double GetMedian() { Collections.sort(list); if (list.size() % 2 == 1) { return Double.valueOf(list.get(list.size() / 2)); } BigDecimal dc1 = new BigDecimal(list.get(list.size() / 2 - 1)); BigDecimal dc2 = new BigDecimal(list.get(list.size() / 2)); BigDecimal divide = dc1.add(dc2).divide(new BigDecimal(2)); return divide.doubleValue(); } }
List<Integer> stream = new ArrayList(8); public void Insert(Integer num) { stream.add(num); Collections.sort(stream); } public Double GetMedian() { int len = stream.size(); int middleIndex = len/2; if(len%2 == 0) { return (double)(stream.get(middleIndex) + stream.get(middleIndex-1))/2; } else { return (double)stream.get(middleIndex); } }
import java.util.*; public class Solution { //构建一个大顶堆和一个小顶堆 //大顶堆里最大的值小于小顶堆的最小的值,把两个中位数依次维护到大顶堆的根节点和小顶堆的根节点 //如果数字个数为奇数,则中位数为小顶堆的根节点。数字为偶数,则中位数为大顶堆和小顶堆根节点的平均值。 int count = 0; //默认为小顶堆 PriorityQueue<Integer> minHeap = new PriorityQueue<>(); PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a,b)->(b-a)); public void Insert(Integer num) { //目前是总体是偶数,就先放到大顶堆,然后把大顶堆的根节点放到小顶堆里 if(count % 2 == 0){ maxHeap.offer(num); minHeap.offer(maxHeap.poll()); }else{ //总体是奇数,就先放到小顶堆,然后把小顶堆的根节点放到大顶堆里,这是最大的 minHeap.offer(num); maxHeap.offer(minHeap.poll()); } count++; } public Double GetMedian() { //如果总体是偶数,中位数为大顶堆和小顶堆根节点的平均值 if(count % 2 == 0){ //Double封装,直接new一个 return new Double(minHeap.peek() + maxHeap.peek()) / 2; }else{ //如果总体是奇数,中位数为小顶堆的根节点 return new Double(minHeap.peek()); } } }