尋找n個數中最大的k個數,本質上就是尋找最大的k個數中最小的那個,也就是第k大的數。可以使用二分搜尋的策略來尋找n個數中的第k大的數。對於乙個給定的數p,可以在o(n)的時間複雜度內找出所有不小於p的數。尋找第k大的元素:
#include using namespace std;
//快速排序的劃分函式
int partition(int a,int l,int r)
a[l] = a[j];
a[j] = x;
return j;
}//隨機劃分函式
int random_partition(int a,int l,int r)
//線性尋找第k大的數
int random_select(int a,int l,int r,int k)
i = random_partition(a,l,r);//劃分
j = i-l+1;
if(k == j) //遞迴結束,找到第k大的數
return a[i];
if(k < j)
else
return random_select(a,i+1,r,k-j);//遞迴呼叫,在後面部分查詢第k大的數}
int main()
; cout《如果所有n個數都是正整數,且它們的取值範圍不太大,可以考慮申請空間,記錄每個整數出現的次數,然後再從大到小取最大的k個。比如,所有整數都在(0, maxn)區間中的話,利用乙個陣列count[maxn]來記錄每個整數出現的個數(count[i]表示整數i在所有整數中出現的個數)。只需要掃瞄一遍就可以得到count陣列。然後,尋找第k大的元素:
for(sumcount = 0, v = maxn-1; v >= 0; v--)
return v;
極端情況下,如果n個整數各不相同,我們甚至只需要乙個bit來儲存這個整數是否存在(bit位為1或為0),這樣使用的空間可以大大壓縮。
當然也可以使用像計數排序、桶排序等這些以o(n)的時間排序演算法也可以尋找第k大的數,但這也是以空間換時間為代價的。
實際情況下,並不一定保證所有元素都是正整數,且取值範圍不太大。上面的方法仍然可以推廣使用。如果n個數中最大的數vmax,最小的vmin,我們可以把這個區間[vmax,vmin]分成m塊,每個小區間的跨度為d=(vmax-vmin)/m,即[vmin,vmin+d],[vmin+d,vmin+2d]......然後,掃瞄一遍所有元素,統計各個小區間中的元素個數,就可以知道第k大的元素在哪乙個小區間。然後,再在那個小區間中找第k大的數(此時這個小區間中,第k大的數可能就是第t大的數了,這個t和每個小區間的個數有關)。我們需要找乙個盡量大的m,但m的取值受到記憶體的限制。
尋找最大的k個數,使用堆實現,可以看這篇文章:
尋找最大的K個數
方法一 改進的快速排序 分割槽時,根據數p將陣列分為兩部分,設大於p的數個數為a,小於p的數的個數為b。如果,a k,則從這a個數取最大的k個數,若a時間複雜度是o nlogk include includevoid swap float a,float b int fun float n,int ...
尋找最大的K個數
程式設計之美有一道考察多種排序的題目,題目如下 有乙個長度為n的無序陣列,假定其中的每乙個元素都各不相等,求其中最大的k個數。作者對於此題目結合各種排序演算法給出了五種解法思路。解法一 使用快速排序或堆排序對它們元素進行排序,整個排序的時間複雜度為o n lo g2n 然後取出前k個,時間複雜度為o...
尋找最大的K個數
前提條件 有n個無序的數,假定它們各不相等,如何選出其中最大的若干個數 適用於元素數量不多,記憶體中可儲存整個陣列序列。通過快速排序或堆排序對陣列排序,時間複雜度為o n log2n 然後取出前k個數,時間複雜度為o k 總時間複雜度為o n log2n o k 進一步的,可以知道,我們只需要前 k...