如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用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());
}
}
}