分治法|輸出前k大的數(北大MOOC程序設計與算法二 第五週測驗)
給定一個數組,統計前k大的數並且把這k個數從大到小輸出。
輸入
第一行包含一個整數n,表示數組的大小。n < 100000。
第二行包含n個整數,表示數組的元素,整數之間以一個空格分開。每個整數的絕對值不超過100000000。
第三行包含一個整數k。k < n。
輸出
從大到小輸出前k大的數,每個數一行。
輸入樣例
10
4 5 6 9 8 7 1 2 3 0
5
輸出樣例
9
8
7
6
5
解題思想
- 排序後輸出,複雜度O( nlogn )。
分治處理,複雜度O( n+mlogm )。 - 把前m大的數都移到數組最右邊,對這m個數排序
- 如何將前m大的數移到最右邊。設 key=a[0], 像快速排序那樣將 key 移到適當位置,使得比 key 小的元素都在它左邊,比 key 大的都在它右邊。比較 key 此時所在位置即 a[i] 起至數組末尾的元素個數是否滿足m個:小於m,在key左邊再移動適當的數到最右邊;大於m,則往key的右邊再縮小。
代碼
#include<iostream>
#include<algorithm> //偷懶用了sort函數
using namespace std;
const int N=100005;
int a[N];
int n,k; //n是數組元素個數,k是前k個最大的數
void swap(int &a,int &b){
int t;
t=a; a=b; b=t;
return;
}
void array(int a[],int s,int e,int k);
int main()
{
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
cin>>k;
array(a,0,n-1,k);
sort(a+n-k,a+n);
for(int i=0;i<k;i++){
cout<<a[n-1-i]<<endl;
}
return 0;
}
void array(int a[],int s,int e,int k){
if(s>=e)
return;
int key=a[s];
int i=s,j=e;
while(i!=j){
while(j>i&&a[j]>=key){
--j;
}
swap(a[i],a[j]);
while(i<j&&a[i]<=key){
++i;
}
swap(a[i],a[j]);
}
if((e-i+1)<k
array(a,s,i-1,k-e+i-1);
else if((e-i+1)>k)
array(a,i+1,e,k);
else
return;
}