【剑指Offer】面试题64:数据流中的中位数
2017-07-29 12:03
260 查看
整理自剑指Offer
牛客网https://www.nowcoder.com/questionTerminal/9be0172896bd43948f8a32fb954e1be1
一:题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
二:解题思路
由于数据从一个数据流中读出来的,数据的数目随着时间的变化而增加,如何选择一个容器存储数据,使插入一个数据后有序 与 计算中位数的时间复杂度性能最优?
如果利用两个指针去寻找中位数
奇数:P1与P2指向同一个位置
偶数:P1,P2指向中间的两个位置(排序后)
整个容器被分成两部分,位于容器左部分的数据比右边的小
P1指向数据左部分最大的数
P2指向数据右边最小的数
如果能够保证数据容器左边的数据小于右边的数据,这样即使左右两边的数据没有排序,也可以根据左边最大的数及右边最小的数得到中位数。
如何快速从一个容器中找到最大的数?----大顶堆实现这个数据容器
如何快速从一个容器中找到最小的数?---小顶堆
要考虑的细节问题:
1.保证数据平均分配在两个堆中:因此两个堆中数目之差不能超过1
2.要保证大顶堆中所有的数据小于小顶堆中的数据
三:代码实现
大顶堆-小顶堆
class Solution {
public:
vector<int> max;//存放大顶堆
vector<int> min; //存放小顶堆
bool isInvalidInput=false;
//当前数据总数为偶数时,插入小顶堆,奇数时,插入大顶堆--保证大顶堆与小顶堆数据平衡
//插入大顶堆前,现将数据插入小顶堆,再将最小值插入到大顶堆中,保证大顶堆元素小于小顶堆元素
//同理,插入小顶堆的元素,现将数据插入到大顶堆,再将最大值插入到小顶堆中,保证小顶堆的元素大于大顶堆元素
void Insert(int num){
//偶数-插入小顶堆
if((min.size()+max.size())%2==0){
//将数据插入大顶堆,找到大顶堆中最大的元素
if(max.size()>0 && num<max[0]){
// push_heap (_First, _Last),要先在容器中加入数据,再调用push_heap ()
max.push_back(num);//先将元素压入容器
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(); //在容器中删除
}
//如果max为空 或者 num大于大顶堆最大值,则将元素直接插入小顶堆
min.push_back(num);//插入小顶堆
push_heap(min.begin(),min.end(),greater<int>());//调整小顶堆
}//if
else{
//奇数--插入大顶堆
if(min.size()>0 && num>min[0]){
// push_heap (_First, _Last),要先在容器中加入数据,再调用push_heap ()
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(); //从容器中删除
}
//如果小顶堆为空,或者num小于小顶堆最小值
max.push_back(num); //直接插入大顶堆
push_heap(max.begin(),max.end(),less<int>());//调整大顶堆
}
}
double GetMedian(){
int size=min.size()+max.size();
if(size<=0) //没有元素,抛出异常
{
isInvalidInput=true;
return 0; //throw exception("No numbers are available");
}
if(size%2==0)//偶数
return (max[0]+min[0])/2.0;
else
return min[0];
}
};
优先队列的方式实现
class Solution {
public:
priority_queue<int, vector<int>, less<int> > max; //优先队列,less保证队列中元素按照从大到小排列,即队首元素最大
priority_queue<int, vector<int>, greater<int> > min; //有限队列,greater保证队列中元素按照从小到大排列,即队首元素最小
void Insert(int num)
{
if(max.empty()||num<=max.top())
max.push(num);
else
min.push(num);
//保证max与min中元素个数均衡
if(max.size()==min.size()+2){
min.push(max.top());
max.pop();
}
//如果元素个数为奇数,保证max的队首元素为中位数
if(max.size()+1==min.size()){
max.push(min.top());
min.pop();
}
}
double GetMedian()
{
return max.size()==min.size()?(max.top()+min.top())/2.0 : max.top();
}
};
牛客网https://www.nowcoder.com/questionTerminal/9be0172896bd43948f8a32fb954e1be1
一:题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
二:解题思路
由于数据从一个数据流中读出来的,数据的数目随着时间的变化而增加,如何选择一个容器存储数据,使插入一个数据后有序 与 计算中位数的时间复杂度性能最优?
如果利用两个指针去寻找中位数
N1 | N2 | ... | N2m | N2m+1 |
N1 | N2 | ... | N2m |
整个容器被分成两部分,位于容器左部分的数据比右边的小
P1指向数据左部分最大的数
P2指向数据右边最小的数
如果能够保证数据容器左边的数据小于右边的数据,这样即使左右两边的数据没有排序,也可以根据左边最大的数及右边最小的数得到中位数。
如何快速从一个容器中找到最大的数?----大顶堆实现这个数据容器
如何快速从一个容器中找到最小的数?---小顶堆
要考虑的细节问题:
1.保证数据平均分配在两个堆中:因此两个堆中数目之差不能超过1
2.要保证大顶堆中所有的数据小于小顶堆中的数据
三:代码实现
大顶堆-小顶堆
class Solution {
public:
vector<int> max;//存放大顶堆
vector<int> min; //存放小顶堆
bool isInvalidInput=false;
//当前数据总数为偶数时,插入小顶堆,奇数时,插入大顶堆--保证大顶堆与小顶堆数据平衡
//插入大顶堆前,现将数据插入小顶堆,再将最小值插入到大顶堆中,保证大顶堆元素小于小顶堆元素
//同理,插入小顶堆的元素,现将数据插入到大顶堆,再将最大值插入到小顶堆中,保证小顶堆的元素大于大顶堆元素
void Insert(int num){
//偶数-插入小顶堆
if((min.size()+max.size())%2==0){
//将数据插入大顶堆,找到大顶堆中最大的元素
if(max.size()>0 && num<max[0]){
// push_heap (_First, _Last),要先在容器中加入数据,再调用push_heap ()
max.push_back(num);//先将元素压入容器
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(); //在容器中删除
}
//如果max为空 或者 num大于大顶堆最大值,则将元素直接插入小顶堆
min.push_back(num);//插入小顶堆
push_heap(min.begin(),min.end(),greater<int>());//调整小顶堆
}//if
else{
//奇数--插入大顶堆
if(min.size()>0 && num>min[0]){
// push_heap (_First, _Last),要先在容器中加入数据,再调用push_heap ()
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(); //从容器中删除
}
//如果小顶堆为空,或者num小于小顶堆最小值
max.push_back(num); //直接插入大顶堆
push_heap(max.begin(),max.end(),less<int>());//调整大顶堆
}
}
double GetMedian(){
int size=min.size()+max.size();
if(size<=0) //没有元素,抛出异常
{
isInvalidInput=true;
return 0; //throw exception("No numbers are available");
}
if(size%2==0)//偶数
return (max[0]+min[0])/2.0;
else
return min[0];
}
};
优先队列的方式实现
class Solution {
public:
priority_queue<int, vector<int>, less<int> > max; //优先队列,less保证队列中元素按照从大到小排列,即队首元素最大
priority_queue<int, vector<int>, greater<int> > min; //有限队列,greater保证队列中元素按照从小到大排列,即队首元素最小
void Insert(int num)
{
if(max.empty()||num<=max.top())
max.push(num);
else
min.push(num);
//保证max与min中元素个数均衡
if(max.size()==min.size()+2){
min.push(max.top());
max.pop();
}
//如果元素个数为奇数,保证max的队首元素为中位数
if(max.size()+1==min.size()){
max.push(min.top());
min.pop();
}
}
double GetMedian()
{
return max.size()==min.size()?(max.top()+min.top())/2.0 : max.top();
}
};
相关文章推荐
- 剑指offer 面试题64 数据流中的中位数
- 剑指offer——面试题64:数据流中的中位数
- 剑指offer面试题64 数据流中的中位数(Java实现)
- 【剑指Offer学习】【面试题64:数据流中的中位数】
- 剑指offer-面试题64-数据流中的中位数
- 剑指offer-面试题64:数据流中的中位数
- 【剑指offer】面试题41:数据流的中位数
- 【剑指offer】题64:数据流中的中位数
- 【剑指offer-解题系列(64)】数据流中的中位数
- 剑指offer 64-数据流中的中位数
- 剑指offer——64.数据流中的中位数
- 剑指offer 数据流中的中位数
- 面试题64:数据流中的中位数
- 剑指offer 数据流中的中位数
- 剑指offer-63题 数据流的中位数
- 剑指offer--数据流中的中位数
- 面试题64 数据流中的中位数
- 剑指Offer_63_数据流中的中位数
- 剑指offer——数据流中的中位数(好)(PriorityQueue,Comparator)
- 面试题64:数据流中的中位数