📜  中位数为整数流(运行整数)(1)

📅  最后修改于: 2023-12-03 15:21:34.560000             🧑  作者: Mango

中位数为整数流(运行整数)

介绍

在计算机科学中,中位数是一个数据集的中间值。对于一个有序的整数序列(无论其中数据是有序的还是无序的),其中间位置的数值就是这个序列的中位数。

在实际问题中,有时候需要在数据流中动态地求取中位数,并且要求中位数只能为整数。这个问题可以通过构造两个堆来解决。

算法描述
  1. 维护两个堆 $left$ 和 $right$,其中 $left$ 是小根堆,$right$ 是大根堆。
  2. 数据流中依次到达的数依次加入两个堆中,保持 $left$ 堆和 $right$ 堆中数的个数差不超过 $1$,同时满足 $left$ 堆的所有数都比 $right$ 堆的数小。
  3. 当前数据流的长度为奇数时,中位数为 $right$ 堆的堆顶;否则中位数为 $left$ 堆的堆顶和 $right$ 堆的堆顶的平均数。
代码实现
Python
import heapq

class MedianFinder:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.left_heap = []
        self.right_heap = []

    def addNum(self, num: int) -> None:
        if len(self.left_heap) == len(self.right_heap):
            heapq.heappush(self.left_heap, -heapq.heappushpop(self.right_heap, -num))
        else:
            heapq.heappush(self.right_heap, -heapq.heappushpop(self.left_heap, num))

    def findMedian(self) -> float:
        if len(self.left_heap) == len(self.right_heap):
            return (self.left_heap[0] - self.right_heap[0]) / 2
        else:
            return float(self.left_heap[0])
Java
class MedianFinder {
    
    private Queue<Integer> leftHeap;  // 小根堆
    private Queue<Integer> rightHeap; // 大根堆

    /** initialize your data structure here. */
    public MedianFinder() {
        leftHeap = new PriorityQueue<>();
        rightHeap = new PriorityQueue<>((o1, o2) -> o2 - o1);
    }
    
    public void addNum(int num) {
        if (leftHeap.size() == rightHeap.size()) {
            rightHeap.offer(num);
            leftHeap.offer(rightHeap.poll());
        } else {
            leftHeap.offer(num);
            rightHeap.offer(leftHeap.poll());
        }
    }
    
    public double findMedian() {
        if (leftHeap.size() != rightHeap.size()) {
            return leftHeap.peek();
        } else {
            return (leftHeap.peek() + rightHeap.peek()) / 2.0;
        }
    }
}
时间复杂度

添加一个数的时间复杂度为 $O(\log{n})$,求中位数的时间复杂度为 $O(1)$。

空间复杂度

空间复杂度为 $O(n)$,因为需要维护两个堆。

适用场景

本算法适用于在数据流中动态地求取中位数的情况,尤其是在中位数必须为整数的情况下。