最小的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 ;
    }
};

 

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