中位数:得到正确的浮点数,需加一个1.0* (size&1)==0,注意有括号。
2017-03-28 21:49
316 查看
题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值注意事项:
1.两个整数n,m,(double) n/m的结果还是整除(n/m)的结果,即使前面加了(double),因为它会先算n/m再用double对得到的整数强制转换。
所以正确的用法是(double) 1.0*n/m,这里一定要加一个1.0*,不然就得不到正确的浮点数。
class Solution { public: void Insert(int num) { myset.insert(num); } double GetMedian() { int len=myset.size(); if(len%2==0){ return (double)((getKthval(len/2)+getKthval(len/2-1))*(1.0)/2); //这个地方一定要加个*1.0,因为(double)(整/整)=整。 }else{ return (double) getKthval(len/2); } } int getKthval(int k){ int cnt=0; for(multiset<int>::iterator it=myset.begin();it!=myset.end();++it){ if(cnt==k){ return *it; } ++cnt; } return 0; } private: multiset<int> myset; };
解法二:
对于数据流,对应的就是在线算法了,一道很经典的题目就是在1亿个数中找到最大的前100个数,这是一道堆应用题,找最大的前100个数,那么我们就创建一个大小为100的最小化堆,每来一个元素就与堆顶元素比较,因为堆顶元素是目前前100大数中的最小数,前来的元素如果比该元素大,那么就把原来的堆顶替换掉。 那么对于这一道题呢?如果单纯的把所有元素放到一个数组里,每次查找中位数最快也要O(n),综合下来是O(n^2)的复杂度。我们可以利用上面例子中的想法,用一个最大堆来维护当前前n/2小的元素,那么每次找中位数只到取出堆顶就可以了。但是,有一个问题,数据要动态增长,有可能之前被替换掉的元素随着元素的增加又跑回来了,所以我们不能单纯得向上题一样把元素丢掉,我们可以再用一个最小化堆来存前n/2大的元素。
分析
获取中位数有多种方法,但是各种方法的时间效率不一。下面是多种方法的时间复杂度的比较:有图可以知道使用AVL二叉平衡树的方法和使用最大堆最小堆的方法是总的时间复杂度最优的。但是AVL二叉平衡树没有现成的数据结构的实现,因此可以考虑Java集合中的PriorityQueue优先队列(也就是堆,默认为小根堆)来实现比较高校的中位数查找。
思路:考虑将数据序列从中间开始分为两个部分,左边部分使用大根堆表示,右边部分使用小根堆存储。每遍历一个数据,计数器count增加1,当count是偶数时,将数据插入小根堆;当count是奇数时,将数据插入大根堆。当所有数据遍历插入完成后(时间复杂度为O(logn),如果count最后为偶数,则中位数为大根堆堆顶元素和小根堆堆顶元素和的一半;如果count最后为奇数,则中位数为小根堆堆顶元素。
//当数据总数为偶数时,新加入的元素,应当进入小根堆
//(注意不是直接进入小根堆,而是经大根堆筛选后取大根堆中最大元素进入小根堆) //1.新加入的元素先入到大根堆,由大根堆筛选出堆中最大的元素
注意:
1.&的优先级低于==的优先级。 所以 (size&1)==0,注意有括号。
2.求中位数可以使用大小堆,大小堆用STL的优先级队列来操作比较简单。
3. priority<int,vector<int>,less<int>> maxheap; 大顶堆 9,8,7,6,5,4
priority<int,vector<int>,greater<int>> minheap;小顶堆 1,2,3,4,5,6
class Solution { public: void Insert(int num) { int size=maxheap.size()+minheap.size(); if((size&1)==0){//草泥马,==的优先级比&高,所以这里一定要有(),调试了大半天. minheap.push(num); maxheap.push(minheap.top()); minheap.pop(); }else{ maxheap.push(num); minheap.push(maxheap.top()); maxheap.pop(); } } double GetMedian() { int size=maxheap.size()+minheap.size(); if((size&1)==0){ return (minheap.top()+maxheap.top())*1.0/2; }else{ return maxheap.top(); } } private: priority_queue<int,vector<int>,less<int>> maxheap; priority_queue<int,vector<int>,greater<int>> minheap; };
解法三:
class Solution { public: void Insert(int num) { //大根堆始终保持“中间值” if(maxheap.empty()||maxheap.top()>num) maxheap.push(num); else minheap.push(num); if(maxheap.si c37c ze()+1==minheap.size()) {//始终保持两个堆的大小差不大于1 maxheap.push(minheap.top()); minheap.pop(); } if(maxheap.size()==minheap.size()+2){//这里不能=+1,因为可能上一步致使。 minheap.push(maxheap.top()); maxheap.pop(); } } double GetMedian() { return minheap.size()==maxheap.size()?((minheap.top()+maxheap.top())*1.0/2):maxheap.top(); } private: priority_queue<int,vector<int>,less<int>> maxheap; priority_queue<int,vector<int>,greater<int>> minheap; };
相关文章推荐
- SQL 的 or注意事项 要正确使用括号
- 把二分查找算法写正确需要注意的地方<转>
- 宏定义函数指针类型&函数返回左值类值 1。宏定义不分配内存,变量定义分配内存。 2。宏名和参数的括号间不能有空格 3。宏替换只作替换,不做计算,不做表达式求解 //下面是正确的标准的写法 typedef int(FUNC1)(int in); ty
- iOS 字符串长度计算boundingRectWithSize遇到 " \r\n"的时候,后面的字符串长度返回0 在swift中使用pod导入第三方库时,注意事项
- eclipse配置外部tomcat需要注意的问题。(怎样让request.getSession().getServletContext().getRealPath("/")得到正确的路径结果)
- glGetString(GL_VERSION)、 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max)为何老是得不到正确的值
- React 中import时如何正确使用花括号'{ }',以及default,export的用法注意事项
- [原创]在C#中改变系统时间 && 得到系统时间改变通知
- 如何正确得到FAT文件系统剩余容量
- Control Study -> 用获取路径方法得到圆形窗体(如将: PictureBox变成圆形)
- 在客户使用透明代理的情况下正确得到其IP地址
- 在Struts中,用向导生成Form, Action&Jsp,如果删除Form需要注意事项
- 推荐一个CLDC1.0上运行的浮点类库
- 正确使用mysql + MFC的一个要注意问题
- linux->windows移植注意事项
- 浮点库的连接问题(针对有的时候scanf("%f",&fn);出现的异常)
- 对于"容量分别为A与B的两个水桶,是否能够通过互相倒水可以得到1~MAX(A,B)所有容量的水"问题的分析
- 正确使用String类的几点注意
- JavaScript Tip/Trick: 动态创建Table时,在IE中需要注意的一个问题
- 正确使用String类的几点注意 (转载 只做学习之用)