排序中的TopK問題

面試中常會(huì)被問到的一個(gè)經(jīng)典問題就是給定一個(gè)無序的數(shù)(N個(gè))嘲恍,尋找其中最大(最形) 的K個(gè)(K<N)。

思路一:對(duì)整個(gè)數(shù)據(jù)進(jìn)行排序愈诚,然后選出前K個(gè)她按,可以選擇快速排序、堆排序和歸并排序炕柔,其時(shí)間復(fù)雜度都可以達(dá)到O(NlogN)
思路二:不進(jìn)行全排列酌泰,只對(duì)最大的K個(gè)排列。如利用冒泡法匕累,每次冒泡取出最大的陵刹,進(jìn)行K次,即可求得TopK.時(shí)間復(fù)雜度是O(n*k), 示例:

def bubble_sort(L, k):
    if k >= len(L):
        pass
    
    for i in range(k):
        # 設(shè)置一個(gè)flag欢嘿,如果某一個(gè)循環(huán)沒有交換衰琐,則整個(gè)有序,停止整個(gè)循環(huán)
        flag = True
        for j in range(len(L) - i - 1):
            if L[j] > L[j+1]:
                flag = False
                L[j], L[j+1] = L[j+1], L[j]
        if flag:
            break
    
    return L[len(L)-k:]

L = [4, 7, 8, 11, 3, 2]
bubble_sort(L, 2)
# [8, 11]

思路三:利用數(shù)據(jù)池思想炼蹦,首先 維護(hù)一個(gè)大小為K的數(shù)據(jù)池羡宙,將前K個(gè)數(shù)放進(jìn)去,然后將原數(shù)據(jù)中剩余的N-K個(gè)數(shù)掐隐,依次與數(shù)據(jù)池中的數(shù)據(jù)做比較狗热,遇到比當(dāng)前數(shù)小的,則替換虑省。此時(shí)的算法時(shí)間復(fù)雜度為O(N*K)

思路四:由于思路二中匿刮,與數(shù)據(jù)池中數(shù)據(jù)做比較時(shí),是順序比較探颈,此處可以優(yōu)化熟丸。如假設(shè)數(shù)據(jù)池中的K個(gè)數(shù)據(jù)是有序的,則比較時(shí)可以借助二分的思想提高效率膝擂,但對(duì)前K個(gè)排序需要O(KlogK)虑啤。更進(jìn)一步,比較的核心是當(dāng)前數(shù)據(jù)池中的數(shù)據(jù)是否有需要替換的架馋,即知道當(dāng)前數(shù)據(jù)池中的最小值即可狞山,而不需要完全排序。

按照這個(gè)思路叉寂,我們維護(hù)一個(gè)大小為K的小根堆萍启,然后依次將原始數(shù)據(jù)中的數(shù)與根對(duì)比,如比根元素大,則進(jìn)行替換并進(jìn)行堆調(diào)整勘纯,即保證數(shù)據(jù)池中數(shù)據(jù)是當(dāng)前的TopK局服,又保證根節(jié)點(diǎn)是最小值。此時(shí)該算法的時(shí)間負(fù)責(zé)度為O(NlogK)

import heapq
def TopK(L, k):
    """
    利用大小為K的堆作為數(shù)據(jù)池驳遵,依次對(duì)比
    tips:headp實(shí)現(xiàn)的是小頂堆淫奔,無法傳入比較函數(shù),若要實(shí)現(xiàn)最小的TopK堤结,可以傳入-item,pop后取負(fù)還原
    """
    r = []
    for j in range(len(L)):
        if j < k:
            heapq.heappush(r, L[j])
        else:
            if r[0] < L[j]:
                heapq.heapreplace(r, L[j])
        
    
    return r

# test
L = [9,7,1,2,6,3]
TopK(L,2)
# [7, 9]

思路五:利用快速排序的分劃函數(shù)找到分劃位置K唆迁,即第K大的數(shù),則其左側(cè)即為所求竞穷√圃穑快速排序的核心是

i = partition(L, low, high)

其中默認(rèn)第一個(gè)元素f是比較基數(shù),然后將數(shù)組L[low, high] 劃分為都比f大的左部分和比f小的右部分瘾带,中間位置是基數(shù)f鼠哥。每次劃分后,如果i > k, 則說明前K個(gè)數(shù)在L[:i]內(nèi)看政,進(jìn)一步在L[:i]中尋找朴恳;如果i < k,則前i個(gè)數(shù)即是最大k個(gè)數(shù)中的i個(gè),繼續(xù)在剩余的L[i:]中尋找第 k - i 大的數(shù)帽衙;如果 i==k ,則說明此時(shí)前i個(gè)即為最大的k個(gè)菜皂。

def partition(L, left, right):
    """
    將L[left:right]進(jìn)行一次快速排序的partition,返回分割點(diǎn)
   :param L: 數(shù)據(jù)List
    :param left: 排序起始位置
   :param right: 排序終止位置
   :return: 分割點(diǎn)
    """
    if left < right:
        key = L[left]
        low = left
        high = right
        while low < high:
            while low < high and L[high] <= key:
                high = high - 1
            L[low] = L[high]
            while low < high and L[low] >= key:
                low = low + 1
            L[high] = L[low]
        L[low] = key
    print(L)
    return low

def topK(K, L):
    if K > len(L):
        pass
    l = 0
    r = len(L) - 1
    j = partition(L, l, r)
    print(j)
    while j != K:
        if j < K:
            l = j + 1
        else:
            r = j
            
        j = partition(L, l, r)
        
    return L[:K]

# test
L = [4,3,1,2,5]
right=len(L)-1
left=0

topK(2,L)
#[5, 4]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末厉萝,一起剝皮案震驚了整個(gè)濱河市恍飘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谴垫,老刑警劉巖章母,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異翩剪,居然都是意外死亡乳怎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門前弯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蚪缀,“玉大人,你說我怎么就攤上這事恕出⊙叮” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵浙巫,是天一觀的道長金蜀。 經(jīng)常有香客問我刷后,道長,這世上最難降的妖魔是什么渊抄? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任尝胆,我火速辦了婚禮,結(jié)果婚禮上护桦,老公的妹妹穿的比我還像新娘含衔。我一直安慰自己,他們只是感情好嘶炭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布抱慌。 她就那樣靜靜地躺著,像睡著了一般眨猎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上强经,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天睡陪,我揣著相機(jī)與錄音,去河邊找鬼匿情。 笑死兰迫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的炬称。 我是一名探鬼主播汁果,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼玲躯!你這毒婦竟也來了据德?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤跷车,失蹤者是張志新(化名)和其女友劉穎棘利,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體朽缴,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡善玫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了密强。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茅郎。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖或渤,靈堂內(nèi)的尸體忽然破棺而出系冗,到底是詐尸還是另有隱情,我是刑警寧澤劳坑,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布毕谴,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏涝开。R本人自食惡果不足惜循帐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望舀武。 院中可真熱鬧拄养,春花似錦、人聲如沸银舱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寻馏。三九已至棋弥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诚欠,已是汗流浹背顽染。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留轰绵,地道東北人粉寞。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像左腔,于是被迫代替她去往敵國和親唧垦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345