题目链接

LeetCode
牛客网

题目描述

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[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

进阶:

  1. 如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
  2. 如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?

    解题思路

    方法一:大顶堆和小顶堆

    用一个大顶堆存小于等于中位数的一半值
    用一个小顶堆存大于等于中位数的一半值
  1. class MedianFinder {
  2. PriorityQueue<Integer> minHeap, maxHeap;
  3. public MedianFinder() {
  4. // 小顶堆 堆顶是最小值 小顶堆里放的都是大于中位数的值
  5. minHeap = new PriorityQueue<Integer>();
  6. // 大顶堆 堆顶是最大值 大顶堆里放的都是小于等于中位数的值
  7. maxHeap = new PriorityQueue<Integer>((a, b) -> b - a);
  8. }
  9. public void addNum(int num) {
  10. minHeap.offer(num);
  11. // 大顶堆中的值的个数大于等于小顶堆
  12. if(maxHeap.size() < minHeap.size()){
  13. maxHeap.offer(minHeap.poll());
  14. }
  15. // 如果小顶堆的最小值小于大顶堆的最大值,将两个值换位置
  16. if(!minHeap.isEmpty() && maxHeap.peek() > minHeap.peek()){
  17. minHeap.offer(maxHeap.poll());
  18. maxHeap.offer(minHeap.poll());
  19. }
  20. }
  21. public double findMedian() {
  22. if(maxHeap.size() == minHeap.size()){
  23. return (double)(maxHeap.peek() + minHeap.peek())/2.0;
  24. }
  25. return (double)maxHeap.peek();
  26. }
  27. }
  28. /**
  29. * Your MedianFinder object will be instantiated and called as such:
  30. * MedianFinder obj = new MedianFinder();
  31. * obj.addNum(num);
  32. * double param_2 = obj.findMedian();
  33. */
  1. class MedianFinder {
  2. PriorityQueue<Integer> minHeap, maxHeap;
  3. public MedianFinder() {
  4. minHeap = new PriorityQueue<Integer>();
  5. maxHeap = new PriorityQueue<Integer>((a, b) -> b - a);
  6. }
  7. public void addNum(int num) {
  8. // 下面代码保证 minHeap 中的最小值大于 maxHeap 中的最大值
  9. minHeap.offer(num);
  10. // minHeap中最小的给maxHeap
  11. maxHeap.offer(minHeap.poll());
  12. // maxHeap中最大的给minHeap
  13. if(minHeap.size() < maxHeap.size()){
  14. minHeap.offer(maxHeap.poll());
  15. }
  16. }
  17. public double findMedian() {
  18. if(minHeap.size() > maxHeap.size()){
  19. return (double)minHeap.peek();
  20. }
  21. return ((double)minHeap.peek() + (double)maxHeap.peek()) / 2.0;
  22. }
  23. }
  24. /**
  25. * Your MedianFinder object will be instantiated and called as such:
  26. * MedianFinder obj = new MedianFinder();
  27. * obj.addNum(num);
  28. * double param_2 = obj.findMedian();
  29. */
  • 时间复杂度 findMedian() O(1) addNum() O(log n)
  • 空间复杂度 O(n)