剑指 Offer 40. 最小的k个数

剑指 Offer 40. 最小的k个数

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

思路

方法一:排序

对原数组从小到大排序后取出前 k 个数即可。时间复杂度为O(nlogn)

方法二:堆

用一个大根堆实时维护数组的前 k 小值。时间复杂度为O(nlogk)

方法三:快排思想

注意,题目只需要返回最小的 k 个数字,而没有要求这 k 个数字一定是有序的。

期望复杂度为O(n):n+n/2+n/4+...n/n = 2n-1

最坏情况下的时间复杂度O(n^2)

代码

方法三

partition不用判断l<=r,因为k<=arr.size()

class Solution {
public:
    int partition(vector<int> &arr, int l, int r) {
        int pivot = arr[l];
        int i = l + 1;
        for (int j = i; j <= r; j++) {
            if (arr[j] < pivot) {
                swap(arr[j], arr[i]);
                i += 1;
            }
        }
        swap(arr[l], arr[i-1]);
        return i-1;
    }
    int calc(vector<int> &arr, int l, int r, int k) {
        int i = partition(arr, l, r);
        if (i - l == k) return i - 1;
        if (i - l + 1 == k) return i;
        if (k > i - l + 1) return calc(arr, i+1, r, k - (i-l+1));
        return calc(arr, l, i-1, k);
    }
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        int i = calc(arr, 0, arr.size()-1, k);
        vector<int> ans(arr.begin(), arr.begin()+i+1);
        return ans;
    }
};

方法二

class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        vector<int> ans;
        if (k == 0) return ans;
        priority_queue<int> q;
        for (int i = 0; i < k; ++i) {
            q.push(arr[i]);
        }
        for (int i = k; i < arr.size(); ++i) {
            if (arr[i] < q.top()) {
                q.pop();
                q.push(arr[i]);
            }
        }
        while (!q.empty()) {
            ans.push_back(q.top());
            q.pop();
        }
        // reverse(ans.begin(), ans.end());
        return ans;
    }
};
posted @ 2022-05-26 18:44  沐灵_hh  阅读(18)  评论(0编辑  收藏  举报