尋找最大的K個數 TOP K演算法

2021-06-08 08:31:27 字數 1178 閱讀 1189

前言:

本文是對程式設計之美第2.5節以及博文的一些總結和心得

問題描述:

有很多個無序的數,怎麼從中選出其中最大的若干數呢?

這個問題中的很多可以是幾個數也可以使成百上億的數,針對此問題我們有以下解法:

解法一:

咱們先簡單的理解,要求乙個序列中最小的k個數,按照慣有的思維方式,很簡單,先對這個序列從小到大排序,然後輸出前面的最小的k個數即可。

至於選取什麼的排序方法,我想你可能會第一時間想到快速排序,我們知道,快速排序平均所費時間為n*logn,然後再遍歷序列中前k個元素輸出,即可,總的時間複雜度為o(n*logn+k)=o(n*logn)。但這只能針對資料量不大的情況下可以實現。

解法二:

類似快速排序的劃分方法,n個數儲存在陣列s中,再從陣列中隨機選取乙個數x(隨機選取樞紐元,可做到線性期望時間o(n)的複雜度),把陣列劃分為sa和sb倆部分,sa<=x<=sb,

1,如果要查詢的k個元素小於sa的元素個數,則返回sa中較小的k個元素;

2,否則返回sa中k個小的元素+sb中小的k-|sa|個元素。

這樣遞迴下去,不斷把問題分解成更小的問題,平均時間複雜度o(nlog2k)。

解法三:

解法四:

我們已經得到了三個解法,不過這三個解法有個共同的地方,就是需要對資料訪問多次,那麼就有下乙個問題,如果n很大呢,100億?

當然,更好的辦法是維護k個元素的最小堆,原理與上述第2個方案一致,即用容量為k的最小堆儲存最先遍歷到的k個數,並假設它們即是最大的k個數,建堆費時o(k)後,有k1kmax,更新堆(用時logk),否則不更新堆。這樣下來,總費時o(k+(n-k)*logk)=o(n*logk)

解法五:

計數排序,時間複雜度雖能達到o(n),但限制條件太多,我們必須假設所有n個整數都是正整數,且他們的取值範圍不大,才可以考慮申請空間,記錄每個整數出現的次數,然後再從大到小取最大的k個數。

綜合考慮我們一般選取上面的解法四來做我們的演算法,也就是我們常常說的top k演算法。

演算法 尋找最大k個數

對於這個問題,最容易想到的辦法就是給陣列排個序,如果使用快速排序,時間複雜度是o nlogn 但事實上我們只需要尋找這k個數,排序的方法顯然做了多餘的事情。那麼,能不能在這個基礎上優化一下呢?我們知道,快速排序的思想是 在陣列中選中乙個支點,以這個支點將陣列劃分成兩部分s1,s2,保證s1所有元素小...

尋找最大的k個數,TopK問題的C 實現

2億個整數中求最大的100萬之和 題目 有乙個檔案中儲存了2億個整數,每個整數都以 分隔。求最大的100萬個整數之和。演算法 1.首先建立乙個容量為100萬 ntop 的int陣列,從檔案讀取整數填充。2.利用堆維護該100萬條記錄 確保堆頂元素為最小值 3.從檔案中讀取乙個整數與堆頂元素比較,如果...

尋找最大的K個數,Top K問題的堆實現

參考 如果不能把所有資料的資料都一次性放入記憶體,就可以維護乙個大小為k的堆,找最大的k個數,就維護乙個小根堆,堆頂元素為這最大的k個數中的最小元素。具體實現參考下面兩個例子 2億個整數中求最大的100萬之和 題目 有乙個檔案中儲存了2億個整數,每個整數都以 分隔。求最大的100萬個整數之和。演算法...