63.数据流中的中位数
题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
记录
方法一:
排序
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.arr=[]
def Insert(self, num):
self.arr.append(num)
self.arr.sort()
def GetMedian(self,sb):
length=len(self.arr)
return self.arr[length//2] if length%2==1 else (self.arr[length//2]+self.arr[length//2-1])/2.0
有个bug:def GetMedian(self,sb):自己添加一个参数
方法二:
最大堆和最小堆
python中的堆
heapq模块
代码来源:代码(明白意思但是不知道怎么写)
# -*- coding:utf-8 -*-
from heapq import *
class Solution:
def __init__ (self):
self.maxheap = []
self.minheap = []
def Insert(self, num):
if (len(self.maxheap)+len(self.minheap))&1: #当前两个堆的总数为奇数
if len(self.minheap)> 0:
if num > self.minheap[0]:#大于最小堆的数
heappush(self.minheap, num)#新数据插入最小堆
heappush(self.maxheap, -self.minheap[0])#最小堆中的最小插入最大堆
heappop(self.minheap)
else:
heappush(self.maxheap, -num)
else:
heappush(self.maxheap, -num)
else: #当前两个堆的总数为偶数
if len(self.maxheap)> 0: #小于最大堆里的元素
if num < -self.maxheap[0]:
heappush(self.maxheap, -num)#新数据插入最大堆
heappush(self.minheap, -self.maxheap[0])#最大堆中的最大元素插入最小堆
heappop(self.maxheap)
else:
heappush(self.minheap, num)
else:
heappush(self.minheap, num)
#print (self.minheap)
def GetMedian(self,n=None):
if (len(self.maxheap)+len(self.minheap))&1:
mid = self.minheap[0]
else:
mid = (self.minheap[0]+self.maxheap[0])/2.0
return mid
这种题还是不适合用python:
java:
import java.util.*;
public class Solution {
private int count = 0;
private PriorityQueue<Integer> minHeap = new PriorityQueue<>();
private PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1,o2)->o2-o1);
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){//如果是偶数个数 就把小顶堆的根元素和大顶堆的根元素 拿出
return (minHeap.peek() + maxHeap.peek())/2.0;
}
else{//如果是奇数个数 那说明中位数就在小顶堆的根的位置
return minHeap.peek()/1.0;
}
}
}
C++:
class Solution {
public:
vector<int> max;
vector<int> min;
void Insert(int num)
{
if((max.size()&1)==0)//偶数时 ,放入最小堆
{
if(max.size()>0&&num<max[0])//偶数插入小顶堆
{
// push_heap (_First, _Last),要先在容器中加入数据,再调用push_heap ()
max.push_back(num);//先将元素压入容器
//push_heap()是向堆中插入一个元素,并且使堆的规则依然成立
push_heap(max.begin(),max.end(),less<int>());//调整最大堆
num=max[0];//取出最大堆的最大值
//pop_heap(_First, _Last),要先调用pop_heap()再在容器中删除数据
pop_heap(max.begin(),max.end(),less<int>());//把最大堆的堆顶值和最后一个元素交换,删除最大堆的最大值
max.pop_back();//在容器中删除
}
min.push_back(num);//压入最小堆
push_heap(min.begin(),min.end(),greater<int>());//调整最小堆
}
else{//奇数时候,放入最大堆
if(min.size()>0&&num>min[0])
{
min.push_back(num);//先压入最小堆
push_heap(min.begin(),min.end(),greater<int>());//调整最小堆
num=min[0];//得到最小堆的最小值(堆顶)
//pop_heap(_First, _Last),要先调用pop_heap()再在容器中删除数据
pop_heap(min.begin(),min.end(),greater<int>());//删除最小堆的最大值
min.pop_back();//在容器中删除
}
max.push_back(num); // 压入数字
push_heap(max.begin(),max.end(),less<int>());//调整最大堆
}
}
double GetMedian()//获取中位数
{
if(max.si***.size()<=0) return 0;//没有元素,抛出异常
//偶数,取平均
//奇数,取最小堆,因为最小堆数据保持和最大堆一样多,或者比最大堆多1个
return ((max.si***.size()&1)==0)?(max[0]+min[0])/2.0:min[0];
}
};