1. 程式人生 > >劍指offer——資料流中的中位數

劍指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實現合集 題目    在數組中的兩個數字如果前面一個數字大於後面的數字,則這兩個數字組成一