010:输出前k大的数
总时间限制: 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
思想
本题由于只需要最大的k个数有序,而其余n-k个数是不需要有序的,因此可以找到最大的k个数(无论有序有否)再对其进行排序即可。总体的思想就是对部分排序时间更少。
而查找的话,就可以利用一个快速排序中的分治思想,用基准数来将比其大的和比其小的数分在其两旁,当且仅当该基准数(包含该基准数)到数组末尾的元素个数为k时满足要求;而元素个数比k小时(假设此时基准数以及其右边的元素个数为m),就说明还需要在基准数左边进行查找较大的k-m个元素;而当元素个数大于k时,就只需要在基准数右边缩小区间查找即可。
代码
#include<iostream>
#include<algorithm>
using namespace std;
void FindMaxK(int* ar, int l, int r, const int k) {
int i = l, j = r;
int tmp = ar[l];
while (i < j) {
while (i < j && ar[j] >= tmp)
--j;
swap(ar[i], ar[j]);
while (i < j && ar[i] <= tmp)
++i;
swap(ar[i], ar[j]);
}
if (r - i + 1 < k)
FindMaxK(ar, l, i - 1, k - (r - i + 1));//在基准数左边查找剩余个数的元素
else if (r - i + 1 == k)//满足条件
return;
else
FindMaxK(ar, i + 1, r, k);//在基准数右边缩小查找区间
}
void show(int* ar, int k, int n) {
FindMaxK(ar, 0, n - 1, k);
sort(ar + n - k, ar + n);//对末尾最大的k个元素排序并输出即可
for (int i = 0; i < k; ++i)
cout << ar[n - i - 1] << endl;
}
int main() {
int n = 0;
cin >> n;
int* ar = new int[n];
for (int i = 0; i < n; ++i)
cin >> ar[i];
int k = 0;
cin >> k;
show(ar, k, n);
delete[]ar;
return 0;
}