排序中topK那點事(轉)


問題描述:有 N (N>1000000)個數,求出其中的前K個最小的數(又被稱作topK問題)。

 

這類問題似乎是備受面試官的青睞,相信面試過互聯網公司的同學都會遇到這來問題。下面由淺入深,分析一下這類問題。

 

思路1:最基本的思路,將N個數進行完全排序,從中選出排在前K的元素即為所求。有了這個思路,我們可以選擇相應的排序算法進行處理,目前來看快速排序,堆排序和歸並排序都能達到O(NlogN)的時間復雜度。當然,這樣的答案也是無緣offer的。

 

思路2:可以采用數據池的思想,選擇其中前K個數作為數據池,后面的N-K個數與這K個數進行比較,若小於其中的任何一個數,則進行替換。這種思路的算法復雜度是O(N*K),當答出這種算法時,似乎離offer很近了。

 

有沒有算法復雜度更低的方法呢?

 

從思路2可以想到,剩余的N-K個數與前面K個數比較的時候,是順序比較的,算法復雜度是K。怎么在這方面做文章呢? 采用的數據結構是堆。

 

思路3:大根堆維護一個大小為K的數組,目前該大根堆中的元素是排名前K的數,其中根是最大的數。此后,每次從原數組中取一個元素與根進行比較,如小於根的元素,則將根元素替換並進行堆調整(下沉),即保證大根堆中的元素仍然是排名前K的數,且根元素仍然最大;否則不予處理,取下一個數組元素繼續該過程。該算法的時間復雜度是O(N*logK),一般來說企業中都采用該策略處理topK問題,因為該算法不需要一次將原數組中的內容全部加載到內存中,而這正是海量數據處理必然會面臨的一個關卡。如果能寫出代碼,offer基本搞定。

 

還有沒有更簡單的算法呢?答案是肯定的。

 

思路4:利用快速排序的分划函數找到分划位置K,則其前面的內容即為所求。該算法是一種非常有效的處理方式,時間復雜度是O(N)(證明可以參考算法導論書籍)。對於能一次加載到內存中的數組,該策略非常優秀。如果能完整寫出代碼,那么相信面試官會對你刮目相看的。

 

下面,給出思路4的Python代碼:

 

def partition(data,start,end):
    if len(data)==1:
        return 0
    small=start
    p=small+1
    while p<=end:
        if data[p]<data[start]:
            small+=1
            data[p],data[small]=data[small],data[p]
        p+=1
    data[start],data[small]=data[small],data[start]
    return small

def topk(data,k):
    if k==0:
        return None
    if len(data)<=k:
        return data
    left=0
    right=len(data)-1
    s=partition(data,left,right)
    while s+1!=k: #下標加1才能與前k的k進行比較
        if s+1>k:
            right=s-1
        if s+1<k:
            left=s+1
        s=partition(data,left,right)
    
    return data[:k]
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM