题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
本题知识点: 进制转化 排序 堆
class Solution {
public:
void Insert(int num) {
}
double GetMedian() {
}
};
堆
时间复杂度为
O
(
l
o
g
n
)
O(log^n)
O(logn)
该题给了两个函数,一个是用来接收存储数据流的,另一个是用来获取当前数据流中的中位数的。
如果是利用堆的思想的话,就是建立两个堆,分别为大堆和小堆,两个堆所存放的数据量必须相同,否则将数据多的那个堆移到数据少的那个堆中。
Insert函数:
例如进来的数据为5 1 3 2 4,假设默认进入小堆,此时min_heap中为5,1进入后,发现1比5小,但是小堆中数据为2,就要把5放入大堆,1放入小堆,3放入小堆,2放入小堆时,小堆有3个数据,则将小堆中最大的3放入大堆,此时大堆数据为3、5,小堆数据为1、2,最后4放入大堆。
因此Insert函数的操作为
- 若两堆数量相同,入小堆;
- 若此时小堆-大堆>=2,将小堆中最大的移入大堆;
GetMedian函数:
3. 如果小堆-大堆1(奇数个数),小堆中最大的数就是中位数;
4. 如果小堆-大堆0(偶数个数),小堆中最大的数+大堆中最小的树/2为中位数
使用vector容器作为堆
这个是我写的,但是没有通过测试,而且因为没有建堆所以其实时间复杂度还是 O ( n ) O(n) O(n),但不知道哪里错了。
class Solution {
public:
void Insert(int num) {
int max_size = max_heap.size();
int min_size = min_heap.size();
if(min_size-max_size == 0){
min_heap.push_back(num);
}
else{
int max = min_heap[0];
for(int i=1;i<min_size+1;i++){
if(min_heap[i]>max){
max = min_heap[i];
}
}
if(max<num){
max_heap.push_back(num);
}
else{
for(vector<int>::iterator iter=min_heap.begin();iter!=min_heap.end();iter++){
if(*iter==max)
min_heap.erase(iter);
break;
}
max_heap.push_back(max);
min_heap.push_back(num);
}
}
}
double GetMedian() {
int max_size = max_heap.size();
int min_size = min_heap.size();
if(min_size-max_size == 1){
int m = min_heap[0];
for(int i=1;i<min_size+1;i++){
if(min_heap[i]>m){
m = min_heap[i];
}
}
return (double)m;
}
else{
int max = min_heap[0];
for(int i=1;i<min_size+1;i++){
if(min_heap[i]>max){
max = min_heap[i];
}
}
int min = max_heap[0];
for(int i=1;i<max_size+1;i++){
if(max_heap[i]>min){
min = max_heap[i];
}
}
return (max+min)/2;
}
}
private:
vector<int> max_heap;
vector<int> min_heap;
};
https://blog.csdn.net/qq_22613757/article/details/93331581 网上参考,自己写了注释。
class Solution {
public:
void Insert(int num){
if(((min.size() + max.size()) & 0x1 ) == 0){ //偶数个数据,大小堆需要移动
if(max.size() > 0 && max[0] > num){
max.push_back(num); //先把当前数据移到大堆 和我上面写的是反过来的
push_heap(max.begin(), max.end(), less<int>()); //大堆最小元素置顶
num = max[0];
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 && min[0] < num){
min.push_back(num);
push_heap(min.begin(), min.end(), greater<int>());
num = min[0];
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()
{
int size = min.size() + max.size();
if(0 == size){
return 0;
}
double median = 0;
if((size & 0x1) == 1){ //奇数个
median = min[0];
}
else{
median = (min[0] + max[0]) * 0.5; //偶数个
}
return median;
}
private:
vector<int> min;
vector<int> max;
};
排序
比较简单,复杂度为 O ( n l o g n ) O(nlog^n) O(nlogn)(排序最快的方法),还是利用vector存储,每进来一个数据排一次,奇数个返回中间数,偶数个返回中间两数平均数。