尋找最大的K個數

2021-07-05 00:15:09 字數 3337 閱讀 8076

程式設計之美有一道考察多種排序的題目,題目如下:

有乙個長度為n的無序陣列,假定其中的每乙個元素都各不相等,求其中最大的k個數。

作者對於此題目結合各種排序演算法給出了五種解法思路。

解法一:

使用快速排序或堆排序對它們元素進行排序,整個排序的時間複雜度為o(n*lo

g2n),然後取出前k個,時間複雜度為o(k),總時間複雜度o(n*lo

g2n)+o(k)=o(n*lo

g2n).根據題目要求,並不需要後n-kn-k個數有序,而只需要尋找最大k的個數,因此可以用選擇排序和交換排序進行部分排序來篩選最大的k個數,其時間複雜度為o(n*k).

解法二:

利用快速排序思想對資料進行分組,讓其一組資料的任何乙個數都比另一組中的任意數大,整個演算法的時間複雜度是o(n*lo

g2k),其情況如下:

假設n個數儲存在陣列s中,我們從陣列s中隨機的找到乙個元素x,把陣列分成兩部分sa和sb。sa中的元素大於等於x,sb中的元素小於x。

(1)sa中的元素個數小於k,sa中所有的數和sb中最大的k-|sa|個元素就是陣列s中最大的k個數。

(2)sa中的元素的個數大於等於k,則需要返回sa中最大的k個元素。

**實現:

#include 

#include

#include

using namespace std;

//返回基準索引

int partition(int a,int low,int height)

int kbig(int a,int low,int height,int k)

//交換資料

void swap(int *a,int *b)

int main()

; int len=sizeof(a)/sizeof(int);

int k=5;

cout<0,len-1,k)return

0;}

解法三思路:

尋找n個數中最大的k個數,本質上就是尋找最大的k個數中最小的那個,也就是第k大的數,因此可以使用二分搜尋的策略,對乙個給定的數p,可以在o(n)的時間複雜度內找出所有不小於p的數,假如n個常數最大的數為vmax,最小的數為vmin,那麼這n個數中的第k大數一定在區間[vmin,vmax]之間,整個演算法的時間複雜度也為o(n*lo

g2n).

**實現:

#include 

#include

#include

using namespace std;

int find(int*a,int x,int len)

int findkmax(int *a,int

max,int

min,int k,int len,int delta)

return

min;

}int main()

; int len=sizeof(a)/sizeof(int);

int k=5;

//該取值要比所有n個數中的任意兩個不相等的元素差值之最小值都要小

int delta=1;

cout<2000,5,5,len,delta)0;}

解法四思路

如果資料很大,100億多個,這個時候資料不能全部裝入記憶體,所以要求盡可能少地遍歷所有資料,如果能通過逐漸的加入元素來判斷,能就可以解決這問題了,因此可以用最小堆的結構來求出前面已加入元素的前k個數,因此可以構造k個元素的小頂堆來儲存最大的k個數,最小堆的堆頂(y)就是最大的k個數中的最小的乙個,對於每乙個新加入的數x,如果x < y,則不需要更新堆,如果x>y,那麼用x替換掉堆頂的元素y,然後調整小頂堆結構,整個過程遍歷一次陣列元素就行了,因此整個演算法的時間複雜度o(n *lo

g2k ).

**實現:

#include 

#include

#include

using

namespace

std;

//調整堆

void adjustminheap(int *a,int m,int n)

else

break;

}}//建立k個元素最小堆

void createminhead(int *a,int k)

void findkmax(int *a,int n,int *kmax,int k)

}}int main()

; int len=sizeof(a)/sizeof(int);

int k=5;

int * kmax=(int*)malloc(k*sizeof(int));

findkmax(a,len,kmax,k);

for(int i=0;icout

<"\t";

return

0;}

第五中解法思路:

利用計數排序思想,如果所有n個數都是正整數,且它們的取值範圍不太大,可以考慮申請空間,記錄每個整數出現的次數,然後再從大到小取最大的k個,比如,所有整數都在(0,maxn)區間中的話,利用乙個陣列count[maxn]來記錄每個整數出現的個數(count[i]表示整數i在所有整數中出現的個數),我們只須掃瞄一遍就可以得到count陣列,然後尋找第k大的元素,整個演算法時間複雜度為o(n).

**實現:

#include 

#include

#include

using

namespace

std;

#define max 100000

int findkmax(int *a,int k)

return i;

}int main()

; int len=sizeof(a)/sizeof(int);

int count[max]=;

int k=5;

//統計a元素對應出現個數

for(int i=0;icout

0;}

尋找最大的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個無序的數,假定它們各不相等,如何選出其中最大的若干個數 適用於元素數量不多,記憶體中可儲存整個陣列序列。通過快速排序或堆排序對陣列排序,時間複雜度為o n log2n 然後取出前k個數,時間複雜度為o k 總時間複雜度為o n log2n o k 進一步的,可以知道,我們只需要前 k...

尋找最大的K個數

給你n個數,讓你找出其中最大的 k個數。解法1 很多人上來就對其進行排序,選用不同的排序方法有不同的時間複雜度,這裡我們假設使用了最快的快排,時間複雜度為o n logn 通過排序我摘出前 k大的數。但也許快排不是最優的,我們只找最大的k 個數,何必要對所有的數進行排序,我們只需要進行區域性排序即可...