原文链接
给定一个N个数的数组arr[N],任意排列,选出其中最大的K个数。
方法1:排序,取后K个数。复杂度: O(NlogN)
方法2:partition,随意选一个数组中的数key,对数组进行划分,返回位置pos,如果pos右侧的数等于K,则结束,如果大于K,则再对从pos到数组尾的子数组进行partition,如果小于K,则对从数组头到pos位置的子数组进行partition,找出剩下的元素。时间复杂度:O(NlogK)
void printarray(int *arr,int beg,int end)
{
for(int i = end-1; i>=beg-1; --i)
{
cout<<arr[i]<<' ';
}
}
int partition(int *arr,int beg,int end)
{
if(beg<1||beg>end)
{
cout<<"error input"<<'\n';
exit(0);
}
if(beg==end)
return beg;
int i = beg-2;
int j = beg-1;
int key = arr[end-1];
while(j<end-1)
{
if(arr[j]<=key)
{
++i;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
++j;
}
int temp = arr[end-1];
arr[end-1] = arr[++i];
arr[i] = temp;
return i+1;
}
void maxK(int *arr,int beg,int end,int K)
{
if(beg<1||beg>end)
{
cout<<"error input"<<'\n';
exit(0);
}
if(end-beg+1==K)
{
printarray(arr,beg,end);
return;
}
int mid = partition(arr,beg,end);
int tmp = end-mid+1;
if(tmp==K)
printarray(arr,mid,end);
else if(tmp<K)
{
printarray(arr,mid,end);
maxK(arr,beg,mid-1,K-tmp);
}
else
maxK(arr,mid+1,end,K);
}
方法3:最小堆,建立一个K元素的最小堆,用arr的前K个元素初始化,然后从arr的第K+1个元素开始扫描数组,如果大于最小堆的根,则互换元素,并对根做minheap_fy,这样最后最小堆里剩的就是最大的K个元素.时间复杂度:O(NlogK)
void minheap_fy(int *heap,int index,int heapsize)
{
int left = index<<1;
int right = left + 1;
int smallest = index;
if(left<=heapsize&&heap[smallest-1]>heap[left-1])
smallest = left;
if(right<=heapsize&&heap[smallest-1]>heap[right-1])
smallest = right;
if(smallest != index)
{
int temp = heap[index-1];
heap[index - 1] = heap[smallest-1];
heap[smallest-1] = temp;
minheap_fy(heap,smallest,heapsize);
}
}
void build_minheap(int *heap,int heapsize)
{
int temp = heapsize/2;
while(temp>0)
{
minheap_fy(heap,temp,heapsize);
--temp;
}
}
void maxK2(int *arr,int size,int K)
{
if(size<K)
{
cout<<"error K"<<'\n';
return;
}
int *heap = new int[K];
for(int i = 0;i<K;++i)
{
heap[i] = arr[i];
}
build_minheap(heap,K);
for(int i = K; i<size; ++i)
{
if(arr[i]>heap[0])
{
heap[0] = arr[i];
minheap_fy(heap,1,K);
}
}
for(int i = 0;i<K;++i)
cout<<heap[i]<<' ';
delete[] heap;
}
方法4:
如果数的波动不大,或者数全为小范围内的整数,可以考虑用桶排序,用空间换时间,直接取出最大的K个元素即可,桶排序的代码见《线性时间排序》,算法复杂度:O(N).