找出第k大的數

2021-08-26 11:02:32 字數 1641 閱讀 6160

問題:

從乙個陣列裡面,找出第k大的數。

題目很簡單,要想把第k個數找出來,其實也挺容易的。

第一種方法:無非就是先排序,比如用merge sort演算法,整個演算法複雜度為 o(nlgn), 然後找到第k個即可。

第二種方法:如果k很小,比如第五個最大的數,而整個陣列的長度非常的大,那麼,還有一種方法就是,我做k遍找最大的數,每做一遍,就把最大的放在陣列的最後面,然後減少陣列掃瞄的範圍,就可以把第k大的數找出來,這樣做的複雜度就是o(k*n),在k很小的情況下,還是不錯的。

第三種方法:我們可以借助quicksort的思想,把陣列的值分成兩部分,一部分比那個pivot大,一部分比pivot小,因為我們知道pivot在陣列中的位置,所以比較k和pivot的位置就知道第k大的值在哪個範圍,我們不斷的進行recursion, 直到pivot就是第k大的值。時間複雜度,出乎意料,為o(n),但是這是平均複雜度。 為何它的平均複雜度比quicksort的複雜度低呢?重要原因是quicksort要對pivot兩邊的子陣列還要排序,而我們其實只需要對其中乙個進行處理,所以複雜度更低。具體怎麼推導,請參考演算法導論。

但是本文講的是另乙個演算法,叫做select 演算法,它能在時間複雜度為o(n)的情況下找出第k大的數。先把演算法貼出來,然後再講。

第一步:把陣列分成\lfloor n/5 \rfool 這麼多子陣列,每個子陣列裡包含5個數,因為會有無法整出的可能,所以最後乙個子陣列會小於5.

第二步:用insertion sorting 把這5個數排序,然後找出中位數,也就是第3個。

第三步:把獲得的中位數又排序,找出中位數的中位數。如果中位數的個數是偶數,那麼取排好序的第 m/2 個數,m指的是中位數的個數。

第四步:然後呢,把原來的陣列分成兩個部分,一部分比那個「中位數的中位數」大,一部分比那個「中位數的中位數」小。我們可以假設左邊的數大,右邊的數小。然後我們可以得到「中位數的中位數」的位置i.

第五步:如果i = k, 那麼那個「中位數的中位數」就是第k大的數。如果 i < k, 不用說,第k大的在「中位數的中位數」的右邊,否則就在左邊。我們一直recursely 這麼做,那麼就一定能夠找到第k大的值了。

其實,演算法還是比較容易懂得,關鍵的關鍵,是複雜度的分析。如果能夠知道複雜度如何求出來的,那麼,對演算法本身就了解得更清楚。

要講複雜度,首先看乙個圖。

圖中的x 就是「中位數的中位數」, 而且箭頭的方向是從大數指到小數。所以,我們可以知道,至少灰色區域的都比x大,這是整個複雜度分析的關鍵,而,其它點能否說它比x大,我們不能保證。而灰色區域裡最多有多少個數呢?因為x是中位數的中位數,所以,比x大的中位數最少有 [(\lfloor n/5 \rfool) * (1/2) - 2] 個(這個值也是關鍵), 這裡減2是因為要去除x本身,第二呢,還要去除乙個中位數---這個中位數所在的子陣列個數小於5. 所以,最壞最壞的情況,第k大的值不在灰色區域裡,那麼我們就要對剩下部分進行不斷的select。剩餘部分就是n - 3[(\lfloor n/5 \rfool) * (1/2) - 2] = o(7n/10) .

整個過程中,第1,2,4步所需時間為o(n), 注意第2步的複雜度不為o(n^2),第3步的複雜度為 t(n/5),第五步的複雜度為 t(7n/10)。

所以,複雜度的遞迴公式為: t(n) =t(n/5) +t(7n/10) + o(n), 算出來以後t(n) =o(n).

找出第k大的數

描述 使用者輸入n和k,然後接著輸入n個正整數 無序的 程式在不對n個整數排序的情況下,找出第k大的數。注意,第k大的數意味著從大到小排在第k位的數。輸入 n ka1 a2 a3 a4 an輸出 b輸入示例 5 232 3 12 5 89輸出示例 32提示 這是一道很經典的演算法問題,是公司面試的常...

陣列 找出陣列的第k大的數

找出陣列的第k大的數 6,7,8,9,3,2,4,8 第3大的數是4 class solution def call self,nums,k if nums none or len nums 0 return 1 result self.qsort nums,0,len nums 1,k retur...

找出第K小的數

題目描述 查詢乙個陣列的第k小的數,注意同樣大小算一樣大。如 2 1 3 4 5 2 第三小數為3。輸入 輸入有多組資料。每組輸入n,然後輸入n個整數 1 n 1000 再輸入k。輸出 輸出第k小的整數。樣例輸入 6 2 1 3 5 2 2 3 樣例輸出 3 void swap int e1,int...