一刷劍指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);
            }
        }
     }
}

 

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