剑指offer41 数据流的中位数
这也是一道没见过就很懵逼的题。题意确实描述的也不清楚,看了代码才明白是要干啥。
剑指offer上分析了一通确认数据结构的思路。挺好的。
因为是从流读取,我们需要确定一个数据结构来存储这些数据。
首先考虑数组。未排序的数组找中位数操作时间复杂度O(n)(使用40题partition的思路),插入O(1)。排序的数组找中位数O(1),插入O(n)。
排序链表,插入O(n),找中位数可以通过设置指针做到O(1)。
平衡的二叉搜索树可以将插入时间缩短到O(logn),节点中加入左右子树各多少节点的记录找中位数可以做到O(1)。但是太复杂,代码量不是一次面试可以完成的。
最后想到,如果用堆的话,较小的数进入左边的大根堆,较大的数进入右边的小跟堆,这样插入时间可以缩短到O(logn),而找中位数也可以做到O(1)。
其中堆的知识可以看http://www.cnblogs.com/vamei/archive/2013/03/20/2966612.html 来温习。
另外堆排序顺便也温习一下。
堆在c++中有库函数,在java中也有优先队列(堆的别称)。
PriorityQueue API:https://docs.oracle.com/javase/8/docs/api/
思路以上。
import java.util.PriorityQueue; import java.util.Comparator; public class Solution { private int count = 0; private PriorityQueue<Integer> minHeap = new PriorityQueue<>(); private PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>(){ @Override public int compare(Integer o1,Integer o2){ return o2-o1; } }); public void Insert(Integer num) { if((count&1)==0){//当数据总数为偶数时,新加入的元素,应当进入小根堆 //(注意不是直接进入小根堆,而是经大根堆筛选后取大根堆中最大元素进入小根堆) //1.新加入的元素先入到大根堆,由大根堆筛选出堆中最大的元素 maxHeap.add(num); //2.筛选后的【大根堆中的最大元素】进入小根堆 minHeap.add(maxHeap.poll()); }else{ minHeap.add(num); maxHeap.add(minHeap.poll()); } count++; } public Double GetMedian() { if((count&1)==0) return ((double)minHeap.peek()+(double)maxHeap.peek())/2.0; else return (double)minHeap.peek(); } }
运行时间:25ms
占用内存:9760k
注意优先队列的使用,以及优先队列默认是小跟堆,如果想用大根堆,要在优先队列的构造函数里new一个Comparator并重写其compare函数。
compare函数接受两个参数o1,o2。
Parameters:o1 - the first object to be compared.o2 - the second object to be compared.
Returns:a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
另外还有基础的用链表做的方法,可以参考https://www.nowcoder.com/profile/645151/codeBookDetail?submissionId=1521636
代码如下,不难就先不自己实现了:
import java.util.LinkedList; public class Solution { LinkedList<Integer> list = new LinkedList<Integer>(); public void Insert(Integer num) { if (list.size()==0||num < list.getFirst()) { list.addFirst(num); } else { boolean insertFlag = false; for (Integer e : list) { if (num < e) { int index = list.indexOf(e); list.add(index, num); insertFlag = true; break; } } if (!insertFlag) { list.addLast(num); } } } public Double GetMedian() { if (list.size() == 0) { return null; } if (list.size() % 2 == 0) { int i = list.size() / 2; Double a = Double.valueOf(list.get(i - 1) + list.get(i)); return a / 2; } list.get(0); Double b = Double.valueOf(list.get((list.size() + 1) / 2 - 1)); return Double.valueOf(list.get((list.size() + 1) / 2 - 1)); } }

浙公网安备 33010602011771号