最小的k個數


title: 2019-8-26 最小的k個數
tags: 算法,每日一題,矩陣打印


最小的k個數

1. 問題描述

數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。

2. 題目解析

這道題目如果單單只是要得到正確結果的話還是很簡單的,關鍵是如果要使時間複雜度達到O(n),那麼難度就會大很多。另外還要對輸入參數進行判斷。如果 k 大於數組大小,直接返回空數組。另外還要判斷 k是不是小於等於0,如果是也直接返回空數組。還有就是輸入數組爲空的話也直接返回空數組。其他情況正常處理即可。

2.1 具體思路

這裏提供了三種方法:

方法一:對數組進行排序,取前k個元素即可。

方法二:使用大根堆進行求解,大根堆的大小爲k,如果大根堆根節點的值大於當前遍歷到的input的值將大根堆根節點彈出,壓入當前input位置的值。最後輸出大根堆中的k個數即可。

方法三:第三種方法是最巧妙的方法,能夠是時間複雜度達到O(n)。所以重點說一下這種方法。這種方法要借鑑快速排序中的partition思想,partition做的一個事就是選定一個值我們稱爲哨兵,然後數組中小於等於哨兵值的數我們放在哨兵值的左邊,大於哨兵值的數字我們放在其右邊。具體的算法如下:

數組中出現次數過半的數

後面發現這種方法有點問題對於這個用例 5,4,4,4,4,5,4,4 k=7發現通不過。我現在固定選定的哨兵就是最後一個第一次partition之後的結果爲:

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> res;
        if(input.size() < k || k <= 0 || input.size() <= 0) return res;//這裏要對輸入進行判斷,否則要發生錯誤
        if(input.size() == k) return input;
         
        GetLeastNumbers_Solution3(input, k, res);
        return res;
    }
     
    void GetLeastNumbers_Solution1(vector<int> &input, int k, vector<int>& res){//方法一:排序後取前k個數,複雜度O(nlogn)
        sort(input.begin(), input.end());
        for(int i=0; i<k; ++i){
            res.push_back(input[i]);
        }
    }
     
     void GetLeastNumbers_Solution2(vector<int> &input, int k, vector<int>& res){//方法二:使用大根堆的方式,複雜度O(nlogk)
         //以下兩種方法都可以
        //使用優先隊列實現
        priority_queue<int> p;
        for (int i = 0; i < input.size(); ++i) {
            if (p.size() < k) {
                p.push(input[i]);
            }
            else {
                if (p.top() > input[i]) {
                    p.pop();
                    p.push(input[i]);
                }
            }
        }
 
        while (!p.empty()) {
            res.push_back(p.top());
            p.pop();
        }
        
         //使用堆實現
        /*res = vector<int>(input.begin(), input.begin() + k);
        make_heap(res.begin(), res.end());
 
            for (int i = k; i < input.size(); ++i)
            {
                if (input[i] < res[0])
                {
                    //先pop,然後在容器中刪除
                    pop_heap(res.begin(), res.end());//pop_head並不會刪除堆頂元素只是將其放在最後
                    res.pop_back();
                    //先在容器中加入,再push
                    res.push_back(input[i]);
                    push_heap(res.begin(), res.end());
                }
            }*/
     }
    
    void swap(vector<int> &input, int a, int b){
        int temp = input[a];
        input[a] = input[b];
        input[b] = temp;
    }
    
    void GetLeastNumbers_Solution3(vector<int> &input, int k, vector<int>& res){//方法三:使用partition的方式
        int len = input.size();
        int begin = 0, end = len-1;
        
        int sentry = -1;
        while(sentry != k){
            int rand_num =  input[end];
            int less = begin; int great = end;
            
            while(less < great){//partition過程
                if(input[less] > input[end]){
                    swap(input, less, --great);
                }else{
                    ++less;
                }
            }
            
            swap(input, great, end);
            sentry = great;
            
            if(sentry < k){//繼續往左邊走
                begin = sentry;
            }else{//往左邊走
                end = sentry-1;
            }
        }
        
        for(int i=0; i<sentry; ++i){
            res.push_back(input[i]);
        }
    }
};

更多關於編程和機器學習資料請關注FlyAI公衆號。
公衆號二維碼

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