劍指offer——資料流中的中位數
題目描述
如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取資料流,使用GetMedian()方法獲取當前讀取資料的中位數。
作者用到的方法非常巧妙,注意到我們只需要位於中間的兩個數就可以得出中位數,當元素個數為奇數個時可以看成這兩個數一樣。中位數在前半部分它是最大的,右半部分是最小的。我們只要始終知道前半部分數裡的最大的那個數,後半部分裡那個最小的數就可以了,其他的不用關心。這明顯是堆的功用,前半部分用一個最大堆,後半部分建一個最小堆。中位數要保持兩個堆的數目之差不超過1.為了實現平均分配,可以在資料的總數目是偶數時把新資料插入到最小堆中,否則插入最大堆中。
另一個問題是保持最大堆的所有資料都小於最小堆中的資料。如果插入一個數使得總數目和為偶數,根據之前的原則應該插入最小堆中,但是新插入的元素可能比最大堆中的元素小怎麼辦?這就違反了最小堆的資料一定大於最大堆得原則。實際上這裡插入的元素應該是新元素和最大堆中所有元素的最大值,最大堆正好有返回一個最大值的作用,所以新插入的元素先插入最大堆,然後取出最大值再插入最小堆中。如果插入元素使得資料總數目和為奇數,處理方法類似。
class Solution { private: vector<int> min; //陣列中的後一半元素組成一個最小化堆 vector<int> max; //陣列中的前一半元素組成一個最大化堆 public: void Insert(int num) { if(((min.size()+max.size()) & 1) == 0) { //偶數資料的情況下,則在最小堆中插入元素 if(max.size() > 0 && num < max[0]) { max.push_back(num); push_heap(max.begin(), max.end(), less<int>()); num=max[0]; pop_heap(max.begin(), max.end(), less<int>()); max.pop_back(); } min.push_back(num); //把前一半找到的最大值放到後一半中 push_heap(min.begin(), min.end(), greater<int>()); } else { if(min.size() > 0 && num > min[0]) { //奇數資料的情況下,則在最大堆中插入元素 min.push_back(num); push_heap(min.begin(), min.end(), greater<int>()); num=min[0]; pop_heap(min.begin(), min.end(), greater<int>()); min.pop_back(); } max.push_back(num); //把後一半找到的最大值放到前一半中 push_heap(max.begin(), max.end(), less<int>()); } } double GetMedian() { int size=min.size() + max.size(); if(size==0) return -1; double median = 0; if((size&1) != 0) { median = (double) min[0]; } else { median = (double) (max[0] + min[0]) / 2; } return median; } };
更簡潔的寫法:
class Solution { priority_queue<int, vector<int>, less<int> > p; priority_queue<int, vector<int>, greater<int> > q; public: void Insert(int num){ if(p.empty() || num <= p.top()) p.push(num); else q.push(num); if(p.size() == q.size() + 2) q.push(p.top()), p.pop(); if(p.size() + 1 == q.size()) p.push(q.top()), q.pop(); } double GetMedian(){ return p.size() == q.size() ? (p.top() + q.top()) / 2.0 : p.top(); } };
相關推薦
劍指offer——資料流中的中位數
題目描述 如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取資料流,使用GetMedian()方法獲取當前
劍指offer____資料流中的中位數
如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取資料流,使用GetMedian()方法獲取當前讀取資料的中位數。 /* 如何得
劍指offer41——資料流中的中位數(Java版)
給定一個不知大小的資料流,求的其中位數(若資料量為基數,直接輸出中位數;若資料量為偶數,輸出中間兩個數平均值) 使用priorityQueue構建指定排序的兩組數。 private PriorityQueue<Integer> max= new Prio
劍指Offer 字元流中第一個只出現一次的字元
題目: 請實現一個函式用來找出字元流中第一個只出現一次的字元。例如,當從字元流中只讀出前兩個字元”go”時,第一個只出現一次的字元是’g’。當從該字元流中讀出前六個字元”google”時,第一個只出現一次的字元是’l’。如果當前字元流沒有存在出現一次的字元,返回#字元。 樣例 輸入:“g
劍指offer 字元流中第一個不重複的字元 python
題目描述 請實現一個函式用來找出字元流中第一個只出現一次的字元。例如,當從字元流中只讀出前兩個字元"go"時,第一個只出現一次的字元是"g"。當從該字元流中讀出前六個字元“google"時,第一個只出現一次的字元是"l"。 樣例 輸入 "google" 輸出 "ggg#ll
劍指offer------字元流中第一個不重複的字元(java版)
一 題目 請實現一個函式用來找出字元流中第一個只出現一次的字元。例如,當從字元流中只讀出前兩個字元"go"時,第一個只出現一次的字元是"g"。當從該字元流中讀出前六個字元“google"時,第一個只出
【劍指offer】數組中僅僅出現一次的數字(1)
tdi eof 一個 ase pos acc -s ret n) 轉載請註明出處:http://blog.csdn.net/ns_code/article/details/27649027題目描寫敘述:一個整型數組裏除了兩個數字之外,其它的數字都出現了兩次。請敲代碼找出這
劍指offer---刪除鏈表中重復的結點
== blog while logs div cati lis ext 刪除 class Solution { public: ListNode* deleteDuplication(ListNode* pHead) { if (
劍指offer---刪除鏈表中重復的結點2
log color 重復 blog -- turn else col cat 遞歸版本: class Solution { public: ListNode* deleteDuplication(ListNode* pHead) { if
劍指offer:數組中出現次數超過一半的數字
一次 相同元素 log 由於 個數字 csdn tail 第一個 可能 http://blog.csdn.net/qq_27703417/article/details/70948850 數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度為9
[劍指offer] 二進制中1的個數
des offer 表示 其中 signed 輸出 一位 bottom tmp 題目描述 輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼表示。 關鍵詞:補碼, x&1計算x二進制的最後一位 遍歷一次即可: class Solution {
劍指Offer - 判斷數組中是否有一個數出現次數多於一半
div amp 的確 出現 question https 一個數 subject scribe https://www.nowcoder.net/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&tqId=11181
劍指offer-刪除鏈表中重復的節點
nbsp eno cat off span scribe 每次 amp tom 題目描述 在一個排序的鏈表中,存在重復的結點,請刪除該鏈表中重復的結點,重復的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->
【劍指offer】數組中的逆序對。C++實現
AC strong HR mage ont color 數組中的逆序對 master blog 原創文章,轉載請註明出處!博客文章索引地址博客文章中代碼的github地址# 題目# 思路 基於歸並排序的思想統計逆序對:先把數組分割成子數組,再子數組合並的過程中統計
劍指Offer:數組中出現次數超過一半的數字【39】
idt 代碼 因此 java實現 mage 數組 sta brush ati 劍指Offer:數組中出現次數超過一半的數字【39】 題目描述 數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如,輸入一個長度為9的數組{1,2,3,2,2,2,5,4,2}
[劍指offer] --14.連結串列中倒數第k個結點
題目描述 輸入一個連結串列,輸出該連結串列中倒數第k個結點。 /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = v
【劍指Offer】26陣列中出現次數超過一半的數字
題目描述 陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。例如輸入一個長度為9的陣列{1,2,3,2,2,2,5,4,2}。由於數字2在陣列中出現了5次,超過陣列長度的一半,因此輸出2。如果不存在則輸出0。 時間限制:1秒;空間限制:32768K;本題知識點:陣列 解題思路
【Java】 劍指offer(39) 數組中出現次數超過一半的數字
特殊 時間復雜度 方法 term 測試 logs pan vat cnblogs 本文參考自《劍指offer》一書,代碼采用Java語言。 更多:《劍指Offer》Java實現合集 題目 數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入
【劍指Offer】09二進位制中1的個數
題目描述 輸入一個整數,輸出該數二進位制表示中1的個數。其中負數用補碼錶示。 時間限制:1秒;空間限制:32768K 解題思路 將n迴圈移位後與1進行按位與運算,累加輸出結果。 Python程式碼: # -*- coding:utf-8 -*- class Solution:
【Java】 劍指offer(51)數組中的逆序對
邊界 時間復雜度 return tps arr 暫時 大小 target star 本文參考自《劍指offer》一書,代碼采用Java語言。 更多:《劍指Offer》Java實現合集 題目 在數組中的兩個數字如果前面一個數字大於後面的數字,則這兩個數字組成一