一刷剑指offer(30)——最小的k个数

题目:
输入n个整数,找出其中最小的k个数。例如输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

最简单的思路:将输入的n个整数排序,排序之后位于最前面的k个数就是最小的k个数。时间复杂度O(nlogn)。

另一种思路:基于快速排序Partition函数。

基于数组的第k个数字来调整,使得比第k个数字小的所有数字都位于数组左边,比第k个数字大的所有数字都位于数组右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字。

void GetLeastNumbers(int* input,int n,int* output,int k)
{
    if(input==NULL||output==NULL||k>n||n<=0||k<=0)
        return;
    int start=0;
    int end=n-1;
    //Partiton函数返回比较标准值的下标
    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);
        }
    }
    for(int i=0;i<k;++i)
        output[i]=input[i];
}

另一种适合于处理海量数据的方法:基于数据容器

先创建一个大小为k的数据容器来存储最小的k个数字,接下来我们每次从输入的n个整数中读入一个数。

如果容器内已有数字少于k,则直接把这次读入的整数放入容器;

如果容器中已有k个数字,即容器已满,需要找出已有的k个数中的最大值,然后将待插入的整数与之相较,如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;否则抛弃。

//multiset是关联容器的一种,是排序好的集合,并且允许有相同的元素
typedef multiset<int,greater<int>>    intSet;
typedef multiset<int,greater<int>>::iterator    setIterator;

void GetLeastNumbers(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);
            }
        }
     }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章