您的位置:首页 > 职场人生

面试题30:最小的K个数

2015-06-01 20:32 671 查看
题目:输入n个整数,找出其中最小的k个数。

1) On的时间复杂度,同样利用partition快排找到第k个数,然后比它小的都在左边,比他大的都在右边,输出K左边的数。

void GetLeastNumbers(int * numbers,int length,int k)
{
if(numbers==NULL||length<=0||k>length||k<=0)
return;
int start=0;
int end=length-1;
int index=Partition(numbers,length,start,end);
while(index!=k-1)
{
if(index<k-1)
{
start=index+1;
index=Partition(numbers,length,start,end);
}
else
{
end=index-1;
index=Partition(numbers,length,start,end);
}
}

for(int i=0;i<k;i++)
{
cout<<numbers[i]<<endl;
}
}


//快速排序中随机生成一个数字,将此大于此下标位置的数的元素放右边,小于的放左边
int Partition(int * data,int length,int start,int end)
{
if(data==NULL||length<=0||start<0||end>=length)
{
throw new exception("invalid parameters");
}

//在起始位置和结束位置中随机生成一位数
int index=randomInRange(start,end);
//将index位置的数和最后一位交换,放置最后
swap(&data[index],&data[end]);
int small=start-1;
//遍历数组
for(index=start;index<end;index++)
{
if(data[index]<data[end])
{
/*
如果当前数小于分界元素,small++,和index相等,指向当前元素,向后遍历
遇到大于分界元素的,small不变,
直到遇到下一个小于分界元素的,对small再加1,
此时small记录的就是第一个大于分界元素的元素下标,然后交换值
*/
small++;
//如果small不指向当前位置
if(index!=small)
{
//交换当前元素和small位置的元素
swap(&data[index],&data[small]);
}
}
}

++small;
swap(&data[small],&data[end]);
return small;//返回下标
}

//生成随机数
int randomInRange(int start, int end)
{
srand(time(NULL));

return start + rand()%(end-start+1);
}
//交换两个数的值
void swap(int * a,int * b)
{
int temp=*a;
*a=*b;
*b=temp;
}


1) O(nlogk)的时间复杂度,适合处理海量数据

我们可以先创建一个大小为K的数据容器来存储最小的K个数,接下来我们每次从输入的n个整数中读入一个数,如果容器中已有的数字少于K,则直接把这次读入的整数放入容器中;如果容器中已有K个数,就是容器满了,此时我们不能插入新的数字而只能替换已有的数字了。找出这K个数的最大值,然后拿这次待插入的整数和最大值相比较。如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还大,那么这个数不可能是最小的K个整数之一,于是我们可以抛弃这个数。我们可以用红黑树来实现这个数据容器,或者使用最大堆来实现,非常适合海量数据的处理。

typedef multiset<int, greater<int> >            intSet;
typedef multiset<int, greater<int> >::iterator  setIterator;

void GetLeastNumbers_Solution2(const vector<int>& data, intSet& leastNumbers, int k)
{
leastNumbers.clear();

if(k < 1 || data.size() < k)
return;

vector<int>::const_iterator iter = data.begin();
for(; iter != data.end(); ++ iter)
{
if((leastNumbers.size()) < k)
leastNumbers.insert(*iter);

else
{
setIterator iterGreatest = leastNumbers.begin();

if(*iter < *(leastNumbers.begin()))
{
leastNumbers.erase(iterGreatest);
leastNumbers.insert(*iter);
}
}
}
}


java:

可以使用TreeSet,TreeSet中可以使元素按从小到大排序,遍历数组每次和最大的值比较。

public class TopK {

public static void main(String[] args) {
int[] array={0,5,2,7,9,11,12,4,3,6};
PrintTopK(array,3);

}

public static void PrintTopK(int[] array,int k)
{
if(array==null||k<1)
return;

TreeSet<Integer> ts=new TreeSet<Integer>();
for(int i=0;i<array.length;i++)
{
if(ts.size()<k)
{
ts.add(array[i]);//如果容器中不够K个数,直接添加
}
else
{
if(array[i]<ts.last())//当前元素和ts最大值比(treeset中最后一个元素是最大值)
{
ts.remove(ts.last());//移除treeset中的最大值
ts.add(array[i]);//将当前元素插入
}
}
}
System.out.println(ts);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: