剑指offer29_最小的K个数_题解

最小的K个数

题目描述

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

示例1

输入

[4,5,1,6,2,7,3,8],4

返回值

[1,2,3,4]

分析

方案一:堆排序

用一个大根堆实时维护数组的前 \(k\) 小值。

代码

/**
时间复杂度:O(nlongk),
其中 n 是数组 arr 的长度。由于大根堆实时维护前 k 小值,所以插入删除都是 O(log k) 的时间复杂度,最坏情况下数组里 n 个数都会插入,所以一共需要 O(nlogk) 的时间复杂度。
空间复杂度:O(k)
**/
class Solution
{
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
    {
        vector<int> res;
        
        if (k > input.size())
            return res;

        priority_queue<int, vector<int>, greater<int>> pq(input.begin(), input.end());

        while (k--)
        {
            res.push_back(pq.top());
            pq.pop();
        }

        return res;
    }
};

方案二:快速选择

借鉴快速排序的思想,当对数组执行一次 \(Partition\) 函数之后,主元 \(A[p]\) 左侧的元素均小于主元。假设此时主元是 \(A[p]\) 那么 \(A[p]\) 就是 \(A[left, right]\) 中的第 \(p - left + 1\) 大的数。令 \(M\) 表示 \(p - left + 1\)

  • \(K = M\)\(K\) 大的数就是主元 \(A[p]\)

  • \(K < M\)\(K\) 大的数在主元左侧,即 \(A[left...(p-1)]\) 中的第 \(K\) 大,往左侧递归

  • \(K > M\)\(K\) 大的数在主元右侧,即 \(A[p+1...right]\) 中的第 \(K\) 大,往右侧递归

代码

/**
平均时间复杂度:O(n)
最坏时间复杂度:O(n^2)
空间复杂度:O(1)
**/
class Solution2
{
public:
    int Partition(vector<int> &input, int left, int right)
    {
        int pivot = input[left];
        while (left < right)
        {
            //从右到左找到第一个比pivot小的元素
            while (left < right && input[right] >= pivot)
                --right;
            swap(input[left], input[right]);
            //从左到右找到第一个比pivot大的元素
            while (left < right && input[left] <= pivot)
                ++left;
            swap(input[left], input[right]);
        }
        input[left] = pivot;
        return left;
    }
    int QuickSelect(vector<int> input, int left, int right, int k)
    {
        if (left == right)
            return input[left];
        int p = Partition(input, left, right);
        int M = p - left + 1;
        if (M == k)
        {
            return input[p];
        }
        else if (M > k)
        {
            return QuickSelect(input, left, p - 1, k);
        }
        else if (M < k)
        {
            return QuickSelect(input, p + 1, right, k - M);
        }
        return input[left];
    }
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
    {
        vector<int> res;
        int n = input.size();

        if (n == 0 || k > n)
            return res;

        for (int i = 1; i <= k; i++)
        {
            int val = QuickSelect(input, 0, n - 1, i);
            res.push_back(val);
        }
        return res;
    }
};
posted @ 2021-01-03 20:28  RiverCold  阅读(81)  评论(0编辑  收藏  举报