剑指offer 63 求输入流中位数/JAVA

剑指offer 63 求输入流中位数

JZ63

  • 题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数
  • 解题思路:
  1. 因为是输入流,所以直接考虑**优先队列!**那么也就是堆排序。
  2. 如何利用堆排序找出中位数,我们可以先假设已经有一个排好序的数组。那么如何将数组储存进堆中使得直接取出堆顶即为中位数
  3. 答案是:我们可以将小于中位数的数据存入大根堆大于中位数的数据存入小根堆,然后只要取出大根堆和小根堆的堆顶即为中位数。
  4. 如何存入数据?
  5. 我们可以将第一个数据存入大根堆,然后将接下来的数据与大根堆的堆顶比较,如果大于大根堆存入小根堆,如果小于小根堆存入大根堆。这样就可以保证任意大根堆的数据都小于小根堆的数据
  6. 但是这会导致两个堆中的数据量不一致,如何解决?
  7. 假设我们现在有两个数据在大根堆,一个数据在小根堆。然后又有一个数据进来,那么这个数据应该存入小根堆。但是这个数据比小根堆堆顶大,所以我们需要存入大根堆。那么如何解决大根堆数据数量比小根堆多,方法就是将大根堆堆顶存入小根堆。然后再将大根堆有序化即可。
import java.util.Comparator;
import java.util.PriorityQueue;
/**
 * 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值
 * 那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,
 * 那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,
 * 使用GetMedian()方法获取当前读取数据的中位数
 */

/**
 * 算法思想:
 * 因为是输入流,所以直接考虑优先队列,那么也就是堆排序。
 * 如何利用堆排序找出中位数,我们可以先假设已经有一个排好序的数组
 * 那么如何将数组储存进堆中使得直接取出堆顶即为中位数?
 * 我们可以将小于中位数的数据存入大根堆,大于中位数的数据存入小根堆,然后只要取出大根堆和小根堆的堆顶即为中位数
 * 如何存入数据?
 * 我们可以将第一个数据存入大根堆,然后将接下来的数据与大根堆的堆顶比较,如果大于大根堆则存入小根堆,如果小于小根堆则存入大根堆
 * 但是这会导致两个堆中的数据量不一致,如何解决?
 * 假设我们现在有两个数据在大根堆,一个数据在小根堆。然后又有一个数据进来,那么这个数据应该存入小根堆。但是这个数据比小根堆堆顶大,所以我们需要存入大根堆。
 * 那么如何解决大根堆数据数量比小根堆多,方法就是将大根堆堆顶存入小根堆。然后再将大根堆有序化即可。
 */
public class JZ63 {
    int count = 0;
    //小根堆
    PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    //大根堆
    PriorityQueue<Integer> maxHeap = new PriorityQueue<>(11, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2.compareTo(o1);
        }
    });
		//输入数据
    public void Insert(Integer num) {
        count++;
        //偶数个,插入小根堆
        if ( count%2 == 0 ) {
            //如果这个数小于大根堆中最大的数,那么插入大根堆,然后将大根堆中最大的插入小根堆
            if (!maxHeap.isEmpty() && num < maxHeap.peek()) {
                maxHeap.offer(num);
                num = maxHeap.poll();
            }
            minHeap.offer(num);
        } else {
            if (!minHeap.isEmpty() && num > minHeap.peek()){
                minHeap.offer(num);
                num = minHeap.poll();
            }
            maxHeap.offer(num);
        }
    }
		//输出数据
    public Double GetMedian() {
        double re = 0;
        //如果只插入了一个数,那么肯定在大根堆里,直接输出大根堆就OK
        if (count == 1){
            re = maxHeap.peek();
        }

        //偶数
        else if (count%2 == 0){
            //除以2.0 否则为整型
            re = ( minHeap.peek() + maxHeap.peek() )/2.0;
        }
        //单数
        else {
            re = maxHeap.peek();
        }
        return re;
    }

}

你可能感兴趣的:(剑指offer,算法,数据结构,数据分析,堆排序,优先队列)