总时间限制: 10000ms 单个测试点时间限制: 1000ms 内存限制: 65536kB
描述
给定一个数组,统计前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
**解题思路:
1.寻找m大个数,完全可以利用c++sort()函数,倒序输出即可(时间复杂度为O(nlogn))。
2.如果不用此法,利用分治法解决,利用快排的原理将整个数组分成一半的一半的一半的一半……例如,如果第一次分成两半,右边放比所选值key大的,左边放小的,如果左边的数量比m大,那说明多了,应该在右边数列里再分,直到数列数量==m。
3.这只是筛选了m个数,还需要排序,再次利用sort。本次时间复杂度就为O(n+mlogm),就少了一些,主要还是训练分治的方法。
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
void nuoDong(int a[],int s,int e,int k){
if(s>=e)
return ;
int t=a[s];
int i=s,j=e;
while(i!=j){
while(i<j&&t<=a[j]) j--;
swap(a[j],a[i]);
while(i<j&&t>=a[i]) i++;
swap(a[j],a[i]);
}
int num=e-i+1;
if(num==k) return;
if(num>k) nuoDong(a,i+1,e,k);
if(num<k) nuoDong(a,s,i-1,k-num);
}
int main(){
int n;
scanf("%d",&n);
int a[100010];
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int k;
scanf("%d",&k);
nuoDong(a,0,n-1,k);
sort(a+n-k,a+n);
for(int i=n-1;i>=n-k;i--){
printf("%d\n",a[i]);
}
return 0;
}