题目:输入N个整数,找出其中最小的K个数,比如输入4,5,1,6,2,7,3,8这八个数,则最小的四个数字是:1,2,3,4
解法一:O(n)的算法:只有当我们可以修改输入的数组的时候可用
我们可以基于快速排序划分的方法来解决这个问题:如果基于数组的第k个数字来调整,使得比第k个数字小的元素都为与数组的左边,比第k个元素大的元素都位于数组的右边,这样调整后位于数组中左边的k个数,就是最小的k个数
参考代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
int partition(int data[],int len,int start,int end)
{
if(data == NULL || len <=0 || start < 0 || end >=start)
return -1;
int index = start;
swap(data[index],data[end]);
int small = start - 1;
for(index = start;index < end;index++)
{
if(data[index] < data[end])
{
++small;
if(small != index)
swap(data[index],data[small]);
}
}
++small;
swap(data[small],data[end]);
return small;
}
//最小的k个元素
void getLastKNumbers(int *input,int n,int *output,int k)
{
if(input == NULL || output == NULL || n <= 0 || k > n || k<=0)
return;
int start = 0;
int end = n - 1;
int index = partition(input,n,start,end);
while(index != k-1)
{
if(index > k-1)
{
end = index - 1;
index = partition(input,n,start,end);
}
else
{
start = index - 1;
index = partition(input,n,start,end);
}
}
int i;
for(i=0;i<k;i++)
{
output[i] = input[i];
}
}
int main()
{
int data[] = {4,5,1,6,2,7,3,8};
int *output;
getLastKNumbers(data,8,output,4);
int i;
for(i=0;i<4;i++)
cout<<output[i]<<" ";
cout<<endl;
return 0;
}
/*#define MAX(a,b) a>b?a:b
#define MIN(a,b) a>b?b:a
using namespace std;
const int N = 110;
int a[N];
bool cmp(int a,int b)
{
return a<b;
}
int sumOffirstI(int n)
{
int i,sum = 0;
for(i=0;i<=n;i++)
sum += a[i];
return sum;
}
int main()
{
int i,t,n;
cin>>t;
while(t--)
{
cin>>n;
for(i=0;i<n;i++)
cin>>a[i];
sort(a,a+n,cmp);
int sum = a[0];
for(i=1;i<n;i++)
{
sum += sumOffirstI(i);
}
cout<<sum<<endl;
}
return 0;
}*/
/*int a[100010];
int max(int n)
{
int Max,t,i;
Max = a[0];
t = a[0];
for(i=1;i<n;i++)
{
if(t<0)
t = a[i];
else
t+=a[i];
Max = MAX(Max,t);
}
return Max;
}
int min(int n)
{
int i,t,Min;
t = a[0];
Min = a[0];
for(i=1;i<n;i++)
{
if(t>0)
t = a[i];
else
t += a[i];
Min = MIN(Min,t);
}
return Min;
}
int main()
{
int n;
while(cin>>n)
{
int sum = 0,i;
for(i=0;i<n;i++)
{
cin>>a[i];
sum += a[i];
}
cout<<(MAX(max(n),sum-min(n)))<<endl;
}
return 0;
}
*/
/*#include <iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 1010;
struct Node
{
double left;//×î×ó±ß
double right;//×îÓÒ±ß
}nodes[N];
bool cmp(Node a,Node b)
{
return a.left < b.left;
}
int main()
{
int n,d;
while(cin>>n>>d)
{
if(n==0 && d==0)
break;
int i,x,y;
bool flag = true;
for(i=0;i<n;i++)
{
cin>>x>>y;
if(y>d)
{
flag = false;
continue;
}
double temp = sqrt(d*d - x*x);
nodes[i].left = x - temp;
nodes[i].right = x + temp;
}
sort(nodes,nodes+n,cmp);
if(flag)
{
int count = 1;
int Case=1;
double r = nodes[0].right;
for(i=1;i<n;i++)
{
if(nodes[i].left > r)
{
count++;
r = nodes[i].right;
}
else
{
if(nodes[i].right < r)
r = nodes[i].right;
}
}
cout<<"Case "<<Case++<<": "<<count<<endl;
}
else
{
cout<<"-1"<<endl;
}
}
return 0;
}*/
方法二:特别适合处理海量数据
我们可以先创建一个大小为k的集合来存储最小的k个元素,接下来我们每次从输入的n个数中读取一个数,如果集合中已有的数字的个数小于k,则直接把这个数放入到集合中,如果集合中已经有k个数,则找出集合中数的最大值,拿这个数和最大值进行比较,如果小于最大值的话,让其和最大值交换,或者舍弃,另外我们可以使用二叉树来存储集合
#include<iostream>
#include<set>
using namespace std;
typedef multiset<int,greater<int> >intSet;
typedef multiset<int greater<int> >::iterator setIterator;
void getKNUmbers(const vector<int>& data,intSet& leastNumbers,int k)
{
leastNumbers.clear();
if(k < 1 || data.size() <= k)
return;
vector<int>::iterator it = data.begin();
for(;it != data.end();it++)
{
if(leastNumbers.size() < k)
leastNumbers.insert(*it);
else
{
setIterator its = leastNumbers.begin();
if(*it < *(leastNumbers.begin()))
{
leastNumbers.erase(its);
leastNumbers.insert(*it);
}
}
}
}