数据流中的中位数

题目

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

解题

剑指offer上说的很详细 
1.无序数组 
插入:O(1)O(1) 
获取中位数:O(N)O(N) 
利用快排的思想,找到中位数

import java.util.*;
public class Solution {
    ArrayList<Integer> list = new ArrayList<Integer>();
    public void Insert(Integer num) {
        list.add(num);
    }

    public Double GetMedian() {
        int size = list.size();
        int k1 = size>>1;
        int k2 = k1 - 1;
        int m1 = GetKth(k1);
        int m2 = GetKth(k2);
        if( (size&1)==1){
            return 1.0*m1;
        }else{
            return 1.0*(m1 + m2)/2.0;
        }
    }
    public int GetKth(int k) {
        if(k==0)
            return list.get(0);
        int result = -1;
        if(list == null || k<0 || k>list.size())
            return result;
        int left = 0;
        int right = list.size() - 1;
        int id = partition(left,right);
        while(id !=k){
             if(id>k){
                 right = id - 1;
                 id = partition(left,right);
             }else{
                 left = id + 1;
                 id = partition(left,right);
             }
         }
        result = list.get(k);
        return result;
    }
    // 划分位置
    public int partition(int low ,int high){
        int x =list.get(high);
        int i = low - 1;// i  记录较大数id j 较小数id
        for( int j = low;j<= high - 1;j++){
            if( list.get(j) <= x){
                i = i + 1;
                swap(i,j);
            }
        }
        i = i + 1;
        swap(i,high);
        return i;
    }
    public void swap(int i,int j){
        int tmp = list.get(i);
        list.set(i,list.get(j));
        list.set(j,tmp);
    }

}

下面通过排序时间复杂度:O(nlogn)O(nlogn)

import java.util.*;
public class Solution {
    ArrayList<Integer> list = new ArrayList<Integer>();
    public void Insert(Integer num) {
        list.add(num);
    }

    public Double GetMedian() {
        int size = list.size();
        Collections.sort(list);
        if(size%2==1){
            return 1.0*list.get(size/2);
        }else{
            return (list.get(size/2) + list.get(size/2-1))/2.0;
        }
    }

}

2.有序数组 
插入:O(N)O(N) 
获取中位数:O(1)O(1)

import java.util.*;
public class Solution {
    ArrayList<Integer> list = new ArrayList<Integer>();
    public void Insert(Integer num) {
        int i =0;
        while(i<list.size()){
            if(list.get(i)<=num){
                i++;
            }else
                break;
        }
        list.add(-1);
        int j = list.size() -1;
        while(j>i){
            list.set(j,list.get(j-1));
            j--;
        }
        list.set(i,num);
    }

    public Double GetMedian() {
        int size = list.size();
        if(size%2==1){
            return 1.0*list.get(size/2);
        }else{
            return (list.get(size/2) + list.get(size/2-1))/2.0;
        }
    }

}

3.有序链表 
插入:O(N)O(N) 
获取中位数:O(N)O(N)

import java.util.*;

public class Solution {
    LinkedList<Integer> list = new  LinkedList<Integer>();

    public void Insert(Integer num) {
        if(list.size() < 1){
            list.add(num);
            return;
        }
        int i = 0;
        while(i<list.size()){
            if(list.get(i) <=num)
                i++;
            else
                break;
        }
        list.add(i,num);

    }

    public Double GetMedian() {
        if( list.size() < 1 ) return null;
        if((list.size()&1) == 1){
            return list.get(list.size()/2)+0.0;
        }else{
            return (list.get((list.size()-1)/2)+list.get(list.size()/2)+0.0)/2;
        }
    }

}

LinkedList内部实现就是链表,这里获取中位数是需要一个一个的遍历链表的 
剑指offer书上定义两个指针指向两边中间,太复杂,省略了

4.最大堆,最小堆 
插入:O(log(n))O(log(n)) 
获取中位数:O(1)O(1) 
两个堆数据之差不超过1 
抄的程序 
优先队列,可以模型堆吗?

import java.util.*;
import java.util.Comparator;
import java.util.PriorityQueue;

public class Solution {
    int count = 0;
    private PriorityQueue<Integer> minHeap = new PriorityQueue<>(11, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 - o2;
        }
    });
    private PriorityQueue<Integer> maxHeap = new PriorityQueue<>(11, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    });

    public void Insert(Integer num) {
         count++;
        if (count % 2 == 0) {
            maxHeap.offer(num);
            int i = maxHeap.poll();
            minHeap.offer(i);
        } else {
            minHeap.offer(num);
            int i = minHeap.poll();
            maxHeap.offer(i);
        }

    }

    public Double GetMedian() {
        if (count % 2 == 0) {
            return (Double.valueOf(maxHeap.peek()) +Double.valueOf( minHeap.peek())) / 2;
        } else {
            return Double.valueOf(maxHeap.peek());
        }
    }

}

也可以这样理解,两个数组,AB,A内的元素都比B的小,B内的元素都比B的大,A是升序的,B也是升序的 
中位数就是A的最大值和B的最小值的平均值 
插入元素时候,上面程序是根据插入数据的奇数偶数顺序选择插入到对应的AB中,这样很好 
奇数时候插入到A,A最大值插入到B 
偶数时候插入到B,B最小值插入到A 
可以用两个排序数组

其他树实现的太复杂了,省略了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值