最小的K個數(劍指offer 面試題40)

題目描述:

輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4。

解題思路:

方法一:

原理類似於博客數組中出現次數超過一半的數的方法一,參考鏈接:https://blog.csdn.net/Victory_tc/article/details/87566304

方法二:

利用大頂堆(multiset)來存儲最小的k個數;首先當大定堆中元素個數小於K時,將數組中的元素插入其中;然後當大定堆中有了k個以後,將數組中當前遍歷元素與之比較,小於堆頂元素,則堆頂元素不可能是最小的k個數之一,所以將其刪除後,插入當前的數組元素;以此遍歷完數組,大頂推中便是最小的k個數。

方法總結:

1)方法一時間複雜度O(n),但是要變動原數組元素的位置;方法二時間複雜度爲O(nlogk)(大頂堆的插入,刪除時間複雜度都爲O(logk)),適用於處理海量數據(n非常大,以至於不能一次性載入內存中,k較小)。

2)方法一不適合海量數據,變動了原數組,但是時間複雜度較低;方法二適用於海量數據,沒有變動原數組。

通過代碼(C++):

方法一:

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> result;
        if(input.empty() || k > input.size() || k <= 0)
            return result;
        int middle  = k-1;
        int start = 0;
        int end = input.size() - 1;
        int index = partion(input,start,end);
        while(index != middle)
        {
            if(index > middle)
            {
                end = index - 1;
            }
            else
            {
                start = index + 1;
            }
                index = partion(input,start,end);
        }
        //判斷輸入是否存在超過數組長度一半的數
        result.assign(input.begin(),input.begin()+k);
        return result;
    }
    //快速排序的基礎,返回選中的基準值在數組中的位置
    int partion(vector<int>&numbers, int start, int end)
    {
        int len = numbers.size();
        if(numbers.empty() || start < 0 || end >= len)
            return -1;
        //產生start-end的隨機數
        int index = RandomInRange(start,end);
        swap(numbers[index],numbers[end]);
        int small = start - 1;
        for(index = start; index < end; ++index)
        {
            if(numbers[index] < numbers[end])
            {
                ++small;
                if(small != index)
                    swap(numbers[small],numbers[index]);
            }
        }
        ++small;
        swap(numbers[small],numbers[end]);
        return small;
    }
    //產生[start,end]的隨機數
    int RandomInRange(int start,int end)
    {
        std::mt19937 rng;//隨機數類型
        rng.seed(std::random_device()());//初始化隨機數種子
        //創建一個均勻分佈,這個均勻分佈可以等概率(隨機)生成[start,end]區間的整形數字;
        std::uniform_int_distribution<int> dist(start,end);
        return dist(rng);
    }
};

方法二:

#include<set>
class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> result;
        if(input.empty() || k > input.size() || k <= 0)
            return result;
        std::multiset<int,greater<int>> auxiliarySet;
        std::vector<int>::const_iterator iter = input.begin();
        for(; iter != input.end(); ++iter)
        {
            if(auxiliarySet.size() < k)
            {
                auxiliarySet.insert(*iter);
            }
            else
            {
                if(*iter < *(auxiliarySet.begin()))
                {
                    std::multiset<int,greater<int>>::iterator iterSet = auxiliarySet.begin();
                    auxiliarySet.erase(iterSet);
                    auxiliarySet.insert(*iter);
                }
            }
        }
        std::multiset<int,greater<int>>::iterator iterSet = auxiliarySet.begin();
        for(;iterSet != auxiliarySet.end(); ++iterSet)
        {
            result.push_back(*iterSet);
        }
        return result;
    }
};

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