最小的k个数

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

第一个思路:利用大根堆。也是解决top k海量数据的关键

延伸部分(重要)

大堆还是小堆的选择很重要,不是寻找最小的k个元素就要选择小堆,而且恰恰相反。

寻找最小的k个数,其实就是寻找第k个大的元素,即寻找k个数中最大的,

不断调整堆,堆得元素个数是k,堆顶是最大值,遍历完初始数组后,

堆中存在的元素即使我们所要寻找的k个最小元素。

题解:

1:首先选取前K个数建立最大堆(根结点值大于左右结点值)。

2:此后,每次从原数组中取一个元素与根进行比较,如果大于根结点的元素,忽视之,取下一个数组元素继续该过程;

如果小于根结点的元素,则将其加入最大堆,并进行堆调整(和堆顶替换),将根元素移动到最后再删除,
即保证最大堆中的元素仍然是排名前K的数,且根元素仍然最大。



make_heap函数用法

这里使用了make_heap构建堆也可以手动实现堆
/* 先后建一个大根堆,利用make_heap函数, 然后将容器剩余元素比较,
 * 小于堆顶的就调整,(入堆,堆顶元素在弹出),
 *  大于堆顶的跳过
 *  最后对容器排序
 */

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> vec;
        int len =input.size();
        if (len <= 0 || len < k || k <= 0 )
            return vec;
        // 将k个数放入vec,然后构建成大根堆
        for (int i = 0; i < k; i++)
            vec.push_back(input[i]);
        make_heap(vec.begin(), vec.end(), less<int>());

        for(int i = k; i < len; i++)
        {
            if (input[i] > vec.front()) // 当前元素大于大根堆堆顶,跳过
                continue;
            else
            {
                vec.push_back(input[i]);
                // 添加新元素,调整堆
                push_heap(vec.begin(), vec.end());
                // 将堆顶元素调整到最后
                pop_heap(vec.begin(), vec.end()); // 将最大的放到最后,然后对容器最后一个删除
                vec.pop_back();  //删除最后那个元素
            }
        }
        // 上面是将最小的k个放入了vec容器中,但是是乱序的,但是这个题也可以不用排序
        sort_heap(vec.begin(),vec.end());
        return vec;
    }
};

这里是手动实现堆的, 面试常考手写堆排和快排哦
class Solution2 {
public:
    // 首先构建一个大根堆(len 是数组长度,index是第一个非叶子节点下标) 构建长度为len,从index开始
    void adjust(vector<int>&vec, int len, int index)
    {
        if (index > len)  // 递归出口
            return ;

        int left  = 2*index + 1; // index的左孩子
        int right = 2*index + 2; // index的右孩子
        int maxIdx  = index;

        // 将maxidx作为子树的最大值, 在下标不越界的情况下
        if (vec[maxIdx] < vec[left] && left < len)
        {
            maxIdx = left;
        }
        if(vec[maxIdx] < vec[right] && right < len)
        {
            maxIdx = right;
        }
        if (index != maxIdx)  // 最大值不是在堆顶就交换
        {
            swap(vec[index], vec[maxIdx]);
            adjust(vec, len, maxIdx);  // 递归所有的子树,构建
        }
    }
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int len = input.size();
        if (len <= 0 || len < k || k <= 0 )
            return vector<int>();
        vector<int>max_heap;
        for(int i = 0; i < k; i++)
            max_heap.push_back(input[i]);

        // 对k个元素进行构建 小根堆, 循环结束后得到的是一个含有k个元素的大根堆
        for(int i = k/2-1; i >= 0; i--)
            adjust(max_heap, k, i);

        // 对input容器中的剩余元素和堆顶比较
        for(int i = k; i < len; i++)
        {
            if (input[i] < max_heap[0])
            {
                max_heap[0] = input[i];
                adjust(max_heap, k, 0); // 对堆顶元素进行调整
            }
        }
            return max_heap;
    }
};
 

第二个思路就是先进性排序,然后输出,但是这并不是出题者要考察的,

但是我们也给出代码(手写快排)加深印象

//
// Created by LK on 2020/3/15.
//
/*
 * 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
 */
#include <iostream>
#include <vector>
using namespace std;
// 思路一排序
class Solution {
public:
    void quick_sort(vector<int>&arr, int left, int right)
    {
        int i = left;
        int j = right;
        int temp;
        if (left < right)
        {

            temp = arr[left];
            while(i < j)
            {
                // 从后向前找个小的
                while(i < j&& arr[j] >= temp)
                    --j;
                if (i < j)
                    arr[i++] = arr[j];
                // 从前往后找个大的
                while (i <j && temp > arr[i])
                    ++i;
                if (i < j)
                    arr[j--] = arr[i];
            }
            arr[i] = temp;
            quick_sort(arr, left, i-1);
            quick_sort(arr, i+1, right);
        }
    }

    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> result;
        int len = input.size();
        if (k <= 0 || k > len)
            return result;
        quick_sort(input, 0, input.size()-1);
        for(int i = 0; i < k; i++)
            result.push_back(input[i]);
        return result;
    }

};
int main() {
    vector<int> input = {4,5,1,6,2,7,3,8};
    int k = 4;
    Solution s;
    input = s.GetLeastNumbers_Solution(input, k);
    for(int i = 0; i < k; i++)
        cout << input[i]<<" ";
    return 0;
}
原文地址:https://www.cnblogs.com/xiaokang01/p/12505122.html