最小的k個數字-優先隊列大頂堆-快速排序k或中位數-小頂堆大頂堆自建-時間複雜度分析

題目:

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

示例 1

輸入:arr = [3,2,1], k = 2
輸出:[1,2] 或者 [2,1]
示例 2

輸入:arr = [0,1,2,1], k = 1
輸出:[0]

限制

0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處

解題思路:

  • 直接排序,獲取數組v[k]值。
class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        vector<int>re(k,0);
        if(arr.size()<k)return re;
        sort(arr.begin(),arr.end());
        for(int i=0;i<k;i++){
            re[i]=arr[i];
        }
        return re;
    }
};
  • 快速排序改爲快速選擇排序。其實理解一下,這道題就是求中位數的O(n)方法,求第k個數,求前k個數字。而快排其實就是在pivot前面的數組絕對小於pivot後面的數字,然後依次劃分到最小單位求得全排序。這裏將pivot好好設置一下,就可以得到一種新的性能十分優越的方法。
class Solution {
private:
    vector<int>re;
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        if(arr.size()<=k)return arr;
        if(k<=0)return re;
        quicksort(arr,0,arr.size()-1,k);
        return re;
    }
    void quicksort(vector<int>&arr,int low1,int high1,int k){
        int i=0,j=0,low=low1,high=high1,st=low,ed=high;
        int pivot=arr[low];
        while(low<high){
            while(low<high&&arr[high]>=pivot)high--;
            arr[low]=arr[high];
            while(low<high&&arr[low]<pivot)low++;
            arr[high]=arr[low];
        }
        arr[high]=pivot;
        if(low==k){
            for(i=0;i<k;i++){
                re.push_back(arr[i]);
            }
            return;
        }else{
            if(low>k){
                quicksort(arr,st,low-1,k);
            }else{
                quicksort(arr,low+1,ed,k);
            }
        }
    }
};
  • 小頂堆,堆排序一下的事情。後來發現構建所有數組的小頂堆時間消耗和方法一差不多。既然如此,構建大小爲k的小頂堆可不可行呢?可行,但是每次插入新元素的話,很難確定是不是k小範圍內的,好吧,找k小的最大值太麻煩了,後來改成大頂堆了,這樣下來時間代價就小多了,假設每次都要調整一下的話,時間大約也不過O(k)+O((n-k)*logk),時間代價小多了。另外,這次是牛客網上的邊界條件比LeetCodes上的測試更細,LeetCode這次合題意的邊界情況也有一個沒有考慮,就是size==k情況的處理,所以按照牛客網上的條件修改吧。修改版本見最後一個代碼。
class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        buildheap(arr);
        vector<int>re;
        int size=arr.size();
        for(int i=0;i<k;i++){
            re.push_back(arr[0]);
            int tmp=arr[0];
            arr[0]=arr[size-1];
            arr[size-1]=tmp;
            size--;
            AdjustUp(arr,0,size-1);
        }
        return re;
    }
    void buildheap(vector<int>&arr){
        int len=arr.size();
        for(int i=len/2;i>=0;i--){
            AdjustUp(arr,i,len-1);
        }
    }
    void AdjustUp(vector<int>&arr,int st,int ed){
        int i=st;
        int k=st*2;
        int stnum=arr[st];
        while(k<=ed){
            if((k+1)<=ed&&arr[k]>arr[k+1]){
                k++;
            }
            if(stnum>arr[k]){
                arr[i]=arr[k];
                i=k;
                k=2*k;
            }else{
                arr[i]=stnum;
                break;
            }
        }
        arr[i]=stnum;
        return ;
    }
};
時間和方法一居然差不多,不過也正常,調整一下。
class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        vector<int>re;
        if(arr.size()<k){
            return re;
        }
        if(arr.size()==k){
            for(int i=0;i<k;i++){
                re.push_back(arr[i]);
            }
            return re;
        }
        for(int i=k/2;i>=0;i--){
            AdjustDown(arr,i,k-1);
        }
        int size=arr.size();
        for(int i=k;i<size;i++){
            if(arr[i]<arr[0]){
                int tmp=arr[0];
                arr[0]=arr[i];
                arr[i]=tmp;
                AdjustDown(arr,0,k-1);
            }
        }
        for(int i=0;i<k;i++){
            re.push_back(arr[i]);
        }
        return re;
    }
   

    void AdjustDown(vector<int>&arr,int st,int ed){
        int i=st;
        int k=st*2;
        int stnum=arr[st];
        while(k<=ed){
            if((k+1)<=ed&&arr[k]<arr[k+1]){
                k++;
            }
            if(stnum<arr[k]){
                arr[i]=arr[k];
                i=k;
                k=2*k;
            }else{
                arr[i]=stnum;
                break;
            }
        }
        arr[i]=stnum;
        return ;
    }
};

 

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