參考
如果輸入乙個陣列,讓你求中位數,這個好辦,排個序,如果陣列長度是奇數,最中間的乙個元素就是中位數,如果陣列長度是偶數,最中間兩個元素的平均數作為中位數。
如果資料規模非常巨大,排序不太現實,那麼也可以使用概率演算法,隨機抽取一部分資料,排序,求中位數,近似作為所有資料的中位數。
本文說的中位數演算法比較困難,也比較精妙,是力扣第 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,那麼中位數就可以通過兩個堆的堆頂元素快速計算了。
優先佇列就是佇列不是先進先出,而是帶有優先順序,使用的也是heap來實現的。
heapq是python自帶的優先佇列的模組。注意預設最小堆,如果需要最大堆就加上負號。
堆結構分為大頂堆和小頂堆,在heapq中使用的是小頂堆:根節點小於等於孩子節點。
其實拿到堆頂並不需要heapq.nlargest(1, a)而是直接拿a[0]就可以了。確實是,本來就是堆頂,第0個。
heapq.nlargest(1, a)這個函式適用於不是堆的列表直接使用拿到最大或者最小~~相當於再排序了一遍qaq
python
import heapq
#向堆中插入元素,heapq會維護列表heap中的元素保持堆的性質
#heapq把列表x轉換成堆
heapq.heapify(x)
#從堆中刪除元素,返回值是堆中最小或者最大的元素
#從可迭代的迭代器中返回最大的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小
lambda定義匿名函式的語法,首先是lambda關鍵字,表示我們當下定義的是乙個匿名函式。之後跟的是這個匿名函式的引數,我們只用到乙個變數x,所以只需要寫乙個x。如果我們需要用到多個引數,通過逗號分隔,當然也可以不用引數。寫完引數之後,我們用冒號分開,冒號後面寫的是返回的結果。
square =
lambda x: x **
2print
(square(3)
)
資料流的中位數
如何得到乙個資料流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用insert 方法讀取資料流,使用getmedian 方法獲取當前讀取資料的中位數。coding utf ...
資料流的中位數
資料流的中位數 中位數是有序列表中間的數。如果列表長度是偶數,中位數則是中間兩個數的平均值。例如,2,3,4 的中位數是 3 2,3 的中位數是 2 3 2 2.5 設計乙個支援以下兩種操作的資料結構 示例 addnum 1 addnum 2 findmedian 1.5 addnum 3 find...
資料流的中位數
問題定義 不斷有數字過來,問在當前所有數字中的中位數是多少 優先佇列 堆 我們可以用乙個大根堆和乙個小根堆分別維護乙個有序數,使得小根堆的所有數字都大於大根堆,這就要求小根堆的堆頂要大於等於大根堆的堆頂。為了求得中位數,我們需要小根堆和大根堆的數字個數相等或相差一。我們可以用優先佇列實現如下 pri...