剑指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));
     
    }
 
}

 

posted @ 2019-02-27 21:14  大胖子球花  阅读(129)  评论(0)    收藏  举报