程式設計之美 尋找最大的K個數

2021-09-30 10:36:54 字數 4181 閱讀 3234

方法一: 使用partition函式,將陣列分為兩組。partition函式是快速排序中用來把陣列分成兩部分的函式。

(1)分為兩個組,sa和sb。

(2)若sa組的個數大於k,則繼續在sa分組中找取最大的k個數字 。

(3)若sa組中的數字小於k ,其個數為t,則繼續在sb中找取 k-t個數字 。

具體**實現:

[cpp]view plain

copy

print?

"font-size: 16px">#include 

using

namespace std ;  

const

int n = 8 ;   

const

int k = 4 ;  

int partition(int  a ,int low , int high)   

j++ ;        

}  //最後處理a[high]

swap(a[i+1] , a[high]) ;    

return i + 1;       

}  int findk(int  a , int low , int high , int k)  

}  int main()  

;  findk(a , 0 , n - 1 , k) ;    

for(int i = 0 ; i < k ; i++)  

cout<

system("pause") ;    

return 0 ;      

}

#include using namespace std ;

const int n = 8 ;

const int k = 4 ;

int partition(int a ,int low , int high)

j++ ;

}//最後處理a[high]

swap(a[i+1] , a[high]) ;

return i + 1;

} int findk(int a , int low , int high , int k)

}int main()

;findk(a , 0 , n - 1 , k) ;

for(int i = 0 ; i < k ; i++)

cout<

方法二 :

此種方法為常用方法,建立乙個大小為k的堆。每次遍歷陣列時,需要判斷是否需要加入堆中。

堆中儲存著的是最大的k個數字,但是若是需要插入堆中,則需要對堆進行調整時間為o(log k)。

全部的時間複雜度為o(n * log k)。

這種方法當資料量比較大的時候,比較方便。因為對所有的資料只會遍歷一次,第一種方法則會多次遍歷

陣列。 如果所查詢的k的數量比較大。可以考慮先求出k` ,然後再求出看k`+1 到 2 * k`之間的數字,然後

一次求取。

方法三:

利用二分的方法求取top k問題。

首先查詢 max 和 min,然後計算出 mid = (max + min) / 2

該演算法的實質是尋找最大的k個數中最小的乙個。 

**如下:

[cpp]view plain

copy

print?

"font-size: 16px">#include 

using

namespace std ;   

const

int n = 8 ;  

const

int k = 4 ;  

/*利用二分的方法求取top k問題。

首先查詢 max 和 min,然後計算出 mid = (max + min) / 2

該演算法的實質是尋找最大的k個數中最小的乙個。 

*/int find(int * a , int x) //查詢出大於或者等於x的元素個數 

return sum ;  

}  int getk(int * a , int max , int min) //最終max min之間只會存在乙個或者多個相同的數字 

cout<<"end"

}  int main()  

;    

int x = getk(a , 554 , 2) ;   

coutreturn 0 ;      

}

#include using namespace std ; 

const int n = 8 ;

const int k = 4 ;

/*利用二分的方法求取top k問題。

首先查詢 max 和 min,然後計算出 mid = (max + min) / 2

該演算法的實質是尋找最大的k個數中最小的乙個。

*/ int find(int * a , int x) //查詢出大於或者等於x的元素個數

return sum ; }

int getk(int * a , int max , int min) //最終max min之間只會存在乙個或者多個相同的數字

cout<<"end"<

方法4:

如果n個數都是正數,取值範圍不太大,可以考慮用空間換時間。申請乙個包括n中最大值的maxn大小的陣列count[maxn],count[i]表示整數i在所有整數中的個數。這樣只要掃瞄一遍陣列,就可以得到低k大的元素。

[cpp]view plain

copy

print?

for(sumcount = 0, v = maxn -1; v >=0; v--)  

return v;  

for(sumcount = 0, v = maxn -1; v >=0; v--)

return v;

擴充套件:

1. 如果需要找出n個數中最大的k個不同的浮點數呢?比如,含有10個浮點數的陣列(1.5,1.5,2.5,3.5,3.5,5,0,- 1.5,3.5)中最大的3個不同的浮點數是(5,3.5,2.5)。

個人覺得除了最後一種方法不行,其他的都可以。因為最後一種需要是正數。

2. 如果是找第k到第m(0

個人覺得可以用小根堆來先求出m個最大的,然後從中輸出k到m個。

網上答案:可以採用小頂堆來實現,使用對映二分堆,可以使更新的操作達到o(logn)。

4. 在實際應用中,還有乙個「精確度」的問題。我們可能並不需要返回嚴格意義上的最大的k個元素,在邊界位置允許出現一些誤差。當使用者輸入乙個query的時候,對於每乙個文件d來說,它跟這個query之間都有乙個相關性衡量權重f (query, d)。搜尋引擎需要返回給使用者的就是相關性權重最大的k個網頁。如果每頁10個網頁,使用者不會關心第1000頁開外搜尋結果的「精確度」,稍有誤差是可以接受的。比如我們可以返回相關性第10 001大的網頁,而不是第9999大的。在這種情況下,演算法該如何改進才能更快更有效率呢?網頁的數目可能大到一台機器無法容納得下,這時怎麼辦呢?

網上答案:答:

正如提示中所說,可以讓每台機器返回最相關的

k'個文件,然後利用歸併排序的思想,得到所有文件中最相關的

k個。 最好的情況是這

k個文件在所有機器中平均分布,這時每台機器只要

k' = k / n (n

為所有機器總數);最壞情況,所有最相關的

k個文件只出現在其中的某一台機器上,這時

k'需近似等於

k了。我覺得比較好的做法可以在每台機器上維護乙個堆,然後對堆頂元素實行歸併排序。

5. 如第4點所說,對於每個文件d,相對於不同的關鍵字q1, q2, …, qm,分別有相關性權重f(d, q1),f(d, q2), …, f(d, qm)。如果使用者輸入關鍵字qi之後,我們已經獲得了最相關的k個文件,而已知關鍵字**跟關鍵字qi相似,文件跟這兩個關鍵字的權重大小比較靠近,那麼關鍵字qi的最相關的k個文件,對尋找**最相關的k個文件有沒有幫助呢?

解答:肯定是有幫助的。 qi最相關的k個文件可能就是**的最相關的k個文件,可以先假設這k個就是,然後根據問題四的解法獲得k',分別和這k個比較,可以用堆進行比較,從而獲得**最相關的k個文件。由於最開始的k個文件極有可能是最終的k個文件,所以k'和k比較的次數可能並不多。

參考:  

本文出自:

程式設計之美 尋找最大的K個數

有很多個無序數,我們姑且假定他們各不相等,怎麼挑選出其中最大的若干個數呢?如果這個資料量很大,比如1億個,如果所存資料是浮點型呢?我們該怎麼處理呢?分兩部分,第一部分是我個人的解答,第二部分是書上的解答 第一部分 1,如果這個問題裡的資料都是整數,這個問題利用hash對映應該很簡單,就是在開闢乙個陣...

程式設計之美 尋找最大的K個數

有很多個無序數,我們姑且假定他們各不相等,怎麼挑選出其中最大的若干個數呢?如果這個資料量很大,比如1億個,如果所存資料是浮點型呢?我們該怎麼處理呢?分兩部分,第一部分是我個人的解答,第二部分是書上的解答 第一部分 1,如果這個問題裡的資料都是整數,這個問題利用hash對映應該很簡單,就是在開闢乙個陣...

程式設計之美 尋找最大的k個數

有很多無序的數,我們姑且假定它們各不相等,怎麼選出其中最大的若干個數呢?idea 1 先用快速排序或者堆排序進行排序,然後取出最大的k個數,時間複雜度為o nlogn o k o nlogn idea 2 進行k趟最大冒泡或者k次大頂堆的輸出,時間複雜度為o n k 根據k與logn的大小比較,選取...