返回

为用户展现专业解答,助力提升用户体验——基于LeetCode 295 数据流的中位数的深入剖析

前端

深入剖析LeetCode 295:数据流的中位数

问题陈述

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。 例如, [2,3,4] 的中位数是 3 [2,3] 的中位数是 (2 + 3) / 2 = 2.5 设计一个支持以下两种操作的数据结构:

  • addNum(val) - 添加一个整数 val 到数据结构中。
  • findMedian() - 返回目前所有元素的中位数。

示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2

算法概述

为了解决LeetCode 295 数据流的中位数问题,我们提出一种基于最小堆和最大堆的解决方案。基本思路是将输入数据流分成两半:左半部分(最大堆)存储较小的元素,右半部分(最小堆)存储较大的元素。这样,中位数就是两个堆顶元素的平均值(如果输入数据流的长度为偶数)或左堆顶元素(如果输入数据流的长度为奇数)。

实现细节

import heapq

class MedianFinder:

    def __init__(self):
        # 最小堆,存储较大的元素
        self.max_heap = []
        # 最大堆,存储较小的元素
        self.min_heap = []

    def addNum(self, val):
        # 将新元素添加到最小堆
        heapq.heappush(self.min_heap, -val)
        # 将最小堆的根元素(最大值)移动到最大堆
        heapq.heappush(self.max_heap, -heapq.heappop(self.min_heap))

        # 平衡两个堆的大小,确保最大堆始终比最小堆多一个元素
        if len(self.max_heap) > len(self.min_heap):
            heapq.heappush(self.min_heap, -heapq.heappop(self.max_heap))

    def findMedian(self):
        # 如果两个堆的大小相同,中位数是两个堆顶元素的平均值
        if len(self.max_heap) == len(self.min_heap):
            return (self.max_heap[0] - self.min_heap[0]) / 2
        # 否则,中位数是最大堆的根元素
        else:
            return -self.max_heap[0]


# 示例
median_finder = MedianFinder()
median_finder.addNum(1)
median_finder.addNum(2)
print(median_finder.findMedian())  # 输出:1.5
median_finder.addNum(3)
print(median_finder.findMedian())  # 输出:2

算法分析

时间复杂度:

  • addNum操作的时间复杂度为O(log n),其中n是当前数据流的长度。
  • findMedian操作的时间复杂度为O(1),因为中位数可以直接从两个堆顶元素中计算得出。

空间复杂度:

算法的空间复杂度为O(n),因为需要使用两个堆来存储数据。

应用场景

LeetCode 295 数据流的中位数算法在许多场景中都有应用,例如:

  • 在数据分析中,中位数可以用来衡量一组数据的中心趋势。
  • 在机器学习中,中位数可以用来处理异常值。
  • 在网络通信中,中位数可以用来计算数据包的平均延迟。

结语

LeetCode 295 数据流的中位数是一个经典的算法问题,其解决方案需要对数据结构和算法有深入的理解。本文详细介绍了基于最小堆和最大堆的解决方案,并分析了算法的时间复杂度和空间复杂度。希望这篇文章对您理解LeetCode 295 数据流的中位数问题有所帮助。