尋找陣列中的第K大的元素

2021-08-16 10:02:17 字數 1883 閱讀 9329

遇到了乙個很簡單而有意思的問題,可以看出不同的演算法策略對這個問題求解的優化過程。

問題:尋找陣列中的第k大的元素。

最簡單的想法是直接進行排序,演算法複雜度是o(n*logn)。這麼做很明顯比較低效率,因為不要求別的資訊只要計算出第k大的元素。當然,如果在某種情況下需要頻繁訪問第k大的元素就可以先進行一次排序在直接得出結果。

第一種方式是這樣,用選擇排序,冒泡法,或者交換排序這類的排序,對前k個元素進行排序。這三種演算法也許不是最快的排序演算法。但是都有個性質:計算出最大(小)的元素的演算法複雜度是o(n)。這個過程不能中斷,要計算第三大的元素必須建立在已經算出第二大的元素的基礎上(因為每次都是計算當前陣列最大)。所以它的演算法複雜度是o(n*k);

第二種方法是用快速排序的思想。快速排序每次把乙個元素交換到正確的位置,同時把左邊的都方上大的,右邊都放上小的。這個演算法每一次選取乙個樞紐元,排序之後,檢視樞紐元的位置。如果它的位置大於k,就說明,要求出前面乙個子串行的第k大的元素。反之,如果小於k,就說明要求出在後面乙個序列的第k - 前乙個序列的長度個元素。

如此,就把這個問題改變成了乙個可以用快排思想解決的問題。對於快速排序,演算法複雜度是o(n*logn)。而這個演算法的演算法複雜度是o(n)。為什麼呢?

其實這個地方的演算法複雜度分析很有意思。第一次交換,演算法複雜度為o(n),接下來的過程和快速排序不同,快速排序是要繼續處理兩邊的資料,再合併,合併操作的演算法複雜度是o(1),於是總的演算法複雜度是o(n*logn)(可以這麼理解,每次交換用了n,一共logn次)。但是這裡在確定樞紐元的相對位置(在k的左邊或者右邊)之後不用再對剩下的一半進行處理。也就是說第二次插入的演算法複雜度不再是o(n)而是o(n/2),這不還是一樣嗎?其實不一樣,因為接下來的過程是1+1/2+1/4+........ < 2,換句話說就是一共是o(2n)的演算法複雜度也就是o(n)的演算法複雜度。

這個演算法目前我在資料結構和演算法書上和劍指offer上都看到過。算是一種很經典很經典的演算法。原因是因為他通過努力把演算法複雜度在每次遞迴中下降一些,最終讓整個演算法的複雜度下降極多,算是一種十分聰明的做法。

第三種方法很是簡單,但是使用它需要某個條件,也就是輸入陣列的取值範圍很小,最好的情況是能形成完全分布,也就是1000大小的陣列裡面的數字是從1到1000這樣子。首先,生成乙個能夠完全裝下原陣列的陣列,這個地方的裝下是指數組大小等於原陣列最大元素(也許還有優化,但這麼描述簡單一點),比如原陣列是[1,2,3,4,5],我要生成的陣列大小是5,如果原陣列是[5,3,6,10],我要生成的陣列大小是10。接下來遍歷原陣列,把每乙個元素放到第二個陣列對應的下標處,5就放在下標為5的地方(實際過程中要減1,因為是陣列從0開始)。放的過程中增加元素值用來統計這個元素出現的次數。這一過程演算法複雜度是o(n)。接下來,再遍歷生成的陣列,找出第k大的元素。

這個過程的演算法複雜度是多少呢?其實這個和原陣列很有關係,原陣列越離散也就越糟糕。比如原陣列是[1,1000],這樣就十分糟糕。第二部的演算法複雜度是o(m),m是前陣列的最大值。總的演算法複雜度o(n)+o(m);

由此可見第三種方法在這個問題的處理非常不好。雖然第三種方法限制頗多(浮點型和負數還有對原陣列大小的要求),但是第三種方法的實質是一種雜湊。就是把原來的對映關係變成了一種反映射。也就是說如果形成了資料與位址的直接對映。但是這種對映的問題也體現的很明顯,它這麼做也只能算是撿了個漏子,如果輸入陣列稍微一邊,還是一樣要用hash演算法計算其hash值。再把hash值對映到位址上。

第四種方法是用二叉堆來做。對大小為n的陣列構建二叉堆的演算法複雜度是o(n)。然後每次下濾的演算法複雜度是o(logn),一共下濾k次,演算法複雜度是o(n+k*logn)。

這種做法比較適合用來處理輸入陣列極大的情況,原因是如果輸入陣列大到不能放入記憶體,那麼構建二叉堆(優先佇列)的時候就可以只構造乙個k個元素的優先佇列。如果下乙個元素比這個最小堆的堆頂還小就直接pass。第二個原因是演算法二在對付乙個極大的輸入佇列的時候演算法複雜度的乙個常數會很大。

**:

尋找陣列中的第K大元素

一 簡述 使用資料結構堆,實現查詢陣列中的第k大元素。流程如下 陣列內容堆化 因為是查詢第k大,所以使用大根堆 依次取出並刪除堆的根節點 將剩餘元素堆化 取到第k個即為目標元素。二 實現 include include using namespace std intfindkth vector in...

陣列中第k大的元素

問題描述 在未排序的陣列中找到第 k 個最大的元素。請注意,你需要找的是陣列排序後的第 k 個最大的元素,而不是第 k 個不同的元素。示例 1 輸入 3,2,1,5,6,4 和 k 2 輸出 5 示例 2 輸入 3,2,3,1,2,4,5,5,6 和 k 4 輸出 4 說明 你可以假設 k 總是有效...

經典演算法題 尋找陣列中第k大的元素

問題描述 在陣列中找到第 k 大的元素。要求時間複雜度為o n 空間複雜度為o 1 分析 此類問題為排序問題,主要難點在於時間複雜度為o n 採用快速排序演算法進行排序 function quicksort nums,k,start,end var left start,right end var ...