中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
进阶:
如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?
链接:https://leetcode-cn.com/problems/find-median-from-data-stream
思路都放在代码里了。结合代码看味道更好
class MedianFinder { //基本思想 建立两个堆 分别存放一半的数据 //1.保证大根堆的堆顶永远小于小根堆顶 //2.保证两个堆的数据差只为1 public PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(); //小顶堆,默认容量为11 public PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11,new Comparator<Integer> (){ //大顶堆,容量11 @Override public int compare(Integer i1,Integer i2){ return i2-i1; } }); /** initialize your data structure here. */ public MedianFinder() { } public void addNum(int num) { if(maxHeap.isEmpty())//如果大根堆为空 则把数字放入大根堆 { maxHeap.offer(num); return; } //如果两个堆的大小一样 //第一中情况 两个堆的数量一样 保证大根堆的头 比小根堆的头要小 且相差为1 if(maxHeap.size()==minHeap.size()) { //比小根堆头大 放小根堆;比小根堆头小 放大根堆 (这边其实也能和大根堆比都能过) if(num>minHeap.peek()) { minHeap.offer(num); } else { maxHeap.offer(num); } } else if(minHeap.size()>maxHeap.size()) {//如果小根堆多一些,那就和小根堆的数字比 这时候可以在笔记本上画一下 //例子为6 10 11 12/7 if(num>minHeap.peek())//12>10 需要把10弹出到大根 { maxHeap.offer(minHeap.poll()); minHeap.offer(num); } else//7<10 直接去大根 我就是这边的代码写错了 调了很久 { maxHeap.offer(num); } } else if(minHeap.size()<maxHeap.size()) {//如果大根堆多一些 直接和大根堆比 实例 4,3/10 if(num>maxHeap.peek()) { minHeap.offer(num);//10大于4 直接去小根那边 } else//3《4 要先把4送到小根 然后把三放进去 { minHeap.offer(maxHeap.poll()); maxHeap.offer(num); } } } public double findMedian() { double temp; if(maxHeap.size()==minHeap.size()) { return (maxHeap.peek()+minHeap.peek())/2.0;//记得这边转一下啊float } else if(maxHeap.size()>minHeap.size()) { return maxHeap.peek(); } else { return minHeap.peek(); } } } /** * Your MedianFinder object will be instantiated and called as such: * MedianFinder obj = new MedianFinder(); * obj.addNum(num); * double param_2 = obj.findMedian(); */