数据流的中位数--参考labuladong

参考
如果输入一个数组,让你求中位数,这个好办,排个序,如果数组长度是奇数,最中间的一个元素就是中位数,如果数组长度是偶数,最中间两个元素的平均数作为中位数。
如果数据规模非常巨大,排序不太现实,那么也可以使用概率算法,随机抽取一部分数据,排序,求中位数,近似作为所有数据的中位数。
本文说的中位数算法比较困难,也比较精妙,是力扣第 295 题,要求你在数据流中计算中位数

addNum方法时间复杂度 O(logN),findMedian方法时间复杂度 O(1)。

大顶堆和小顶堆合作解决。大顶堆的堆顶和小顶堆的堆顶的平均数就是我们要的中位数。

两个堆需要算法逻辑正确维护,才能保证堆顶元素是可以算出正确的中位数,我们很容易看出来,两个堆中的元素之差不能超过 1。

依次加入到大顶堆和小顶堆里,维护两个堆数目相同,最终取平均数。

简单说**,想要往large里添加元素,不能直接添加,而是要先往small里添加,然后再把small的堆顶元素加到large中;向small中添加元素同理。**

为什么呢,稍加思考可以想明白,假设我们准备向large中插入元素:

如果插入的num小于small的堆顶元素,那么num就会留在small堆里,为了保证两个堆的元素数量之差不大于 1,作为交换,把small堆顶部的元素再插到large堆里。

如果插入的num大于small的堆顶元素,那么num就会成为samll的堆顶元素,最后还是会被插入large堆中。

反之,向small中插入元素是一个道理,这样就巧妙地保证了large堆整体大于small堆,且两个堆的元素之差不超过 1,那么中位数就可以通过两个堆的堆顶元素快速计算了。
数据流的中位数--参考labuladong_第1张图片
优先队列就是队列不是先进先出,而是带有优先级,使用的也是heap来实现的。

heapq是python自带的优先队列的模块。
堆结构分为大顶堆和小顶堆,在heapq中使用的是小顶堆:根节点小于等于孩子节点

注意heapq.heappop 和heapq.heappush之后得到的也是堆。
heapq中创建堆的方法有两种。

heappush(heap, num),先创建一个空堆,然后将数据一个一个地添加到堆中。每添加一个数据后,heap都满足小顶堆的特性。
heapify(array),直接将数据列表调整成一个小顶堆(调整的原理参考上面堆排序的文章,heapq库已经实现了)。



python
import heapq
#向堆中插入元素,heapq会维护列表heap中的元素保持堆的性质
heapq.heappush(heap, item)   # push之后还是堆
#heapq把列表x转换成堆
heapq.heapify(x)  
#从堆中删除元素,返回值是堆中最小或者最大的元素
heapq.heappop(heap)  # heappop面向的是堆,pop之后还是堆


#从可迭代的迭代器中返回最大的n个数,可以指定比较的key------针对列表即可
heapq.nlargest(n, iterable[, key])
#从可迭代的迭代器中返回最小的n个数,可以指定比较的key
heapq.nsmallest(n, iterable[, key])

import heapq
nums = [14, 20, 5, 28, 1, 21, 16, 22, 17, 28]
heapq.nlargest(3, nums)    列表的前n大
# [28, 28, 22]
heapq.nsmallest(3, nums)   列表的前n小
# [1, 5, 14]


laptops = [
    {
     'name': 'ThinkPad', 'amount': 100, 'price': 91.1},
    {
     'name': 'Mac', 'amount': 50, 'price': 543.22},
    {
     'name': 'Surface', 'amount': 200, 'price': 21.09},
    {
     'name': 'Alienware', 'amount': 35, 'price': 31.75},
    {
     'name': 'Lenovo', 'amount': 45, 'price': 16.35},
    {
     'name': 'Huawei', 'amount': 75, 'price': 115.65}
]

cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])```

~~ sorted(nums, key = lambda x : x[1])

lambda定义匿名函数的语法,首先是lambda关键字,表示我们当下定义的是一个匿名函数。之后跟的是这个匿名函数的参数,我们只用到一个变量x,所以只需要写一个x。如果我们需要用到多个参数,通过逗号分隔,当然也可以不用参数。写完参数之后,我们用冒号分开,冒号后面写的是返回的结果。
```python
square = lambda x: x ** 2
print(square(3))

你可能感兴趣的:(剑指offer)