面试题64:数据流中的中位数
来源:互联网 发布:免费机械制图软件 编辑:程序博客网 时间:2024/04/27 10:09
题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
可以将从数据流中读到的数据放入数据容器
1.未排序的数组,可以使用partition函数找到数组的中位数,插入数字和找出中位数的时间复杂度分别是O(1)和O(n)
2.在插入数据的时候对数组排序,插入时间复杂度为O(n),查找中位数O(1)
3.排序的链表,插入数据时间复杂度O(N),如果定义两个指针指向链表中间节点,时间复杂度时O(1)
4.二叉搜索树,插入数据O(logn),当二叉搜索树极度不平衡看起来像排序链表的时候,插入数据时间复杂度仍是O(n),为了得到中位数,可以在结点中添加一个表示子树节点数目的字段,然后可以在O(logn)得到中位数,最差情况仍然需要O(n).
5.AVL树,插入结点O(logn),获取中位数O(1)。
6.最大堆最小堆,如果将数据流中的数字排序,中位数可以由P1 P2指向 的数得到,如果数目是奇数,P1=P2,可以发现排序的时候,P1指向的数据是左边部分最大的数,P2指向的是数据右边最小的数,且左边的数小于右边的数,所以可以将左边的数放入一个大顶堆中,右边的数放入小顶堆中,堆顶就是对应的P1和P2。
插入时间复杂度为O(logn),获取中位数O(1)
步骤:
1.为了使数据平均分配,两个堆中的数目之差不能超过1,所以当数据总数目是偶数时把新的数据插入到最小堆,否则插入到最大堆
2.为了保证最大堆中的所有数据小于最小堆,当数据数目是偶数时,需要插入到小顶堆,但是此时数据比大顶堆中的堆顶的值要小,那么就将数据插入到大顶堆中,因为大顶堆根节点是最大元素,然后将根节点元素插入到小顶堆中。
3.当把数据插入到最大堆中但这个数据大于最小堆的堆顶的值时,与上面情况处理办法一样。
如1 3 7 9 5
(1)先将1插入大顶堆,插入3的时候总数目是2,3大于大顶堆的1,插入到小顶堆,此时
1 3
大顶堆 小顶堆
(2)7的时候总数目为奇数,但是7大于小顶堆的3,插入小顶堆,然后将3插入大顶堆
3 7
1
大顶堆 小顶堆
(3)9插入到小顶堆
3 7
1 9
大顶堆 小顶堆
(4)5<7直接插入到大顶堆5 7
1 9
3
大顶堆 小顶堆
所以中位数为小顶堆的堆顶7
template<typename T>class DynamicArray{public:void Insert(T num){if(((min.size()+max.size())&1)==0)//数据总数为偶数时,在最小堆中插入元素{if(max.size()>0&&num<max[0])//如果最大堆结点个数不为0并且当前数据的值小于最大堆的根节点的值{max.push_back(num);//将数据插入最大堆,插入到末尾push_heap(max.begin(),max.end(),less<T>());//重新调整堆序num=max[0];//获取最大堆根节点的值pop_heap(max.begin(),max.end(),less<T>());//取出堆顶元素,放到vector末尾max.pop_back();//将末尾元素删除}min.push_back(num);//将数据插入最小堆push_heap(min.begin(),min.end(),greater<T>());}else//数据总数为奇数时,在最大堆中插入元素{if(min.size()>0&&num>min[0]){min.push_back(num);push_heap(min.begin(),min.end(),greater<T>());num=min[0];pop_heap(min.begin(),min.end(),greater<T>());min.pop_back();}max.push_back(num);push_heap(max.begin(),max.end(),less<T>());}}//获取中位数T GetMedian(){int size=min.size()+max.size();if(size==0)throw exception("No numbers are available");T median=0;//如果数据总数是奇数if((size&1)==1){median=min[0];//返回小顶堆的堆顶元素}else{median=(max[0]+min[0])/2;//返回两个堆顶的值的和再除以2}return median;}//使用vector模拟大顶堆和小顶堆private:vector<T> min;vector<T> max;};
------来自剑指offer
java:
public class MedianNumber {static TreeSet<Integer> tsMin=new TreeSet<Integer>();//最小堆static TreeSet<Integer> tsMax=new TreeSet<Integer>();//最大堆/** * 题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。 * 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。 * */public static void main(String[] args) {insert(1);insert(3);insert(5);insert(7);insert(9);int median=getMedian();System.out.println(tsMin);System.out.println(tsMax);System.out.println(median);}//Treeset模拟堆,tresset会将插入的元素按大小排列//treeSet中first()方法返回第一个值也就是最小值,last()方法返回最大值//最大堆中放置的元素是中位数左边的数字//最小堆中放置的元素是中位数右边的数字public static void insert(int number){if((tsMin.size()+tsMax.size())%2==0)//数据总数为偶数,将数插入到最小堆{if(tsMax.size()!=0&&number<tsMax.last())//如果插入的元素比最大堆中最大元素还小{//将当前元素先插入到最大堆tsMax.add(number);number=tsMax.last();//获取最大堆中最大的元素tsMax.remove(number);}tsMin.add(number);}else//插入到最大堆{if(tsMin.size()!=0&&number>tsMin.first())//如果插入元素比最小堆的最小元素还大{//将当前元素先插入到最大堆tsMin.add(number);number=tsMin.first();//获取最小堆中最小的元素tsMin.remove(number);}tsMax.add(number);}}public static int getMedian(){int size=tsMin.size()+tsMax.size();if(size%2!=0)return tsMax.last();elsereturn (tsMax.last()+tsMin.first())/2;}}
- 面试题64:数据流中的中位数
- 面试题64:数据流中的中位数
- 【面试题64】数据流中的中位数
- 面试题64:数据流中的中位数
- 《剑指Offer》学习笔记--面试题64:数据流中的中位数
- 【剑指Offer学习】【面试题64:数据流中的中位数】
- 剑指offer-面试题64:数据流中的中位数
- 《剑指offer》面试题64 数据流中的中位数
- 剑指offer--面试题64:数据流中的中位数
- 剑指offer-面试题64-数据流中的中位数
- 剑指offer 面试题64 数据流中的中位数
- 剑指offer面试题[64]-数据流中的中位数
- 【剑指Offer】面试题64:数据流中的中位数
- 面试题71:数据流中的中位数
- 面试题64. 数据流中的中位数
- 面试题_64——数据流中的中位数
- 剑指offer面试题64 数据流中的中位数(Java实现)
- 【剑指offer】面试题41:数据流的中位数
- 1007. 素数对猜想 (20)
- ubuntu下安装搜狗输入法
- 权限控制 数据库设计
- android ViewPager滑动事件讲解
- iOS UIWebView 使用经验集合
- 面试题64:数据流中的中位数
- jQuery Ajax 实例 全解析
- 什么时候用@Resource,什么时候用@service
- Nexue5开启 Google Now , Location History
- ActionBar标题和渐变背景设置
- RTP与RTCP协议介绍
- jQuery中$.fn的用法示例介绍
- HDOJ题目2554 N对数的排列问题(数学)
- 远程文件下载