【21】剑指offer——最小的K个数字

本文介绍两种寻找数组中最小K个数的有效方法。一种使用优先队列实现,时间复杂度为O(nlog(k));另一种采用Partition算法思想,平均时间复杂度接近O(n),更高效且巧妙。

题目描述

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

 

解题思路:

思路1:首先是一个简单的解题思路,利用一个priority_queue的优先队列结构,这个结构的特点是队列首元素是该队列中最大的元素,因此首先将input中的前k个元素压入priority_queue,之后遍历一遍该数组,数组的每一个元素与priority_queue中的首元素进行比较,如果比首元素小则压入priority_queue,弹出首元素即可,时间复杂度主要是priority_queue内部排序造成的O(nlog(k))。

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> ret;
        priority_queue<int> ans;
        int len = input.size();
        if (len < k || k == 0){
            return ret;
        }
        for (int i = 0; i < k; i++){
            ans.push(input[i]);
        }
        
        for (int i = k; i < len; i++){
            if (input[i] < ans.top()){
                ans.pop();
                ans.push(input[i]);
            }
        }
        
        //vector<int> ret;
        int cnt = k;
        while(cnt--){
        ret.push_back(ans.top());
        ans.pop();
        }
        
        return ret;
    }
};

思路2:太巧妙了!利用近似O(n)就可以解决问题的算法!利用partition算法的思想(详情请见我的博客Partition 算法详解 + 应用 + 代码实现(一)),每一次遍历数组的时候,都可以先随机确定一个priovot的值,然后不停遍历数组,大于等于privot的都在privot右边,小于等于privot的都在privot左边,当privot左边的长度恰好为k时,遍历结束,输出这k个元素即为答案。

代码如下:

class Solution {
public:
    int partition(vector<int> &arr, int beginn, int endd){
        int privot = arr[beginn];
        while (beginn < endd){
            while (beginn < endd && arr[--endd] >= privot);
            arr[beginn] = arr[endd];
            while (beginn < endd && arr[++beginn] <= privot);
            arr[endd] = arr[beginn];
        }
        
        arr[endd] = privot;
        return beginn;
    }
    
    
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        
        vector<int> ret;
        int len = input.size();
        if (len < k || k == 0){
            return ret;
        }
        int pos = partition(input, 0, len);
        while (pos + 1 != k){
            if (pos + 1 > k){
                pos = partition(input, 0, pos);
            }
            else if (pos + 1 < k){
                pos = partition(input, pos + 1, len);
            }
        }
        
        for (int i = 0; i < pos + 1; i++){
            ret.push_back(input[i]);
        }
        return ret;
    }
};

小白感叹算法真奇妙

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值