数据流中的中位数;大根堆和小根堆的使用方法教学案例;剑指offer40 最小的k个数也是大根堆实现

最小堆最大堆,给定未排序的数组,找到中位数

from heapq import *
class MedianFinder:
    def __init__(self):
        self.A = [] # 小顶堆,保存较大的一半
        self.B = [] # 大顶堆,保存较小的一半
    def addNum(self, num: int) -> None:
        if len(self.A) != len(self.B):
            heappush(self.B, -heappushpop(self.A, num))
            # heappush(self.A, -heappushpop(self.B, -num))
        else:
            heappush(self.A, -heappushpop(self.B, -num))
            # heappush(self.B, -heappushpop(self.A, num))
#刚开始len(A)=len(B),先将数据存入A,使即使奇数个数据,len(A)>len(B),最后return A[0];如果先存入B,则最后return -B[0]结果一样
#但A是最小堆,所以存入的数据都是正的,保证A[0]是最小值;B是最大堆,python中无最大堆,用存入数据都是负的,保证最小的是最大数的负数,即B[0]是最小数,即最大正数的负数;
#最大堆用负数存入最小堆实现很算法,最小堆pop出的是最小值,对于最大堆来说也是最小值,只不过取相反数是最大的正数,所以也就是pop出的是最大值,即最大堆的意义
    def findMedian(self) -> float:
        # return -self.B[0] if len(self.A) != len(self.B) else (self.A[0] - self.B[0]) / 2.0
        return self.A[0] if len(self.A) != len(self.B) else (self.A[0] - self.B[0])/2
#举个例子[1,2,3,4] -> [-2,-1][3,4]

时间复杂度:O(logn),堆的插入和弹出操作需要 O(logn),查找中位数,即获取堆顶元素需要 O(1)
空间复杂度:O(n),堆空间的消耗
参考链接

本题如果返回浮点数,/2.0在python2中是可以的
import的是heapq,使用的是heappush和heappushpop

剑指offer40 最小的k个数
大根堆的实现用相反数来实现 heapq heapq.heappop heapq.heappush heapq.heappushpop

class Solution(object):
    def getLeastNumbers(self, arr, k):
        """
        :type arr: List[int]
        :type k: int
        :rtype: List[int]
        """
        #最小的k个数,用大根堆来实现,这样前k个数就是最小的,大根堆堆顶是最大值;每次比较堆顶
        if k == 0:
            return []
        maxheap = []
        for i in arr:
            if len(maxheap)<k or -maxheap[0]>i:
                heapq.heappush(maxheap,-i)#大根堆元素小于k 或 堆顶元素较大
                if len(maxheap)>k:
                    heapq.heappop(maxheap)
        return [-x for x in maxheap]

时间复杂度 只需要遍历数组1遍,遍历的时候插入堆,堆的插入和弹出时间复杂度为logn,其实应该是logk,所以整体时间复杂度为O(nlogn)
空间复杂度O(k)堆空间的消耗

你可能感兴趣的:(数据结构-堆,再看几遍,剑指offer)