zoukankan      html  css  js  c++  java
  • 最小的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;
    }
  • 相关阅读:
    洛谷 P6622
    洛谷 P6619
    LOJ 3188
    CF::Gym 102174G
    eJOI2017~2019
    洛谷 P6313
    洛谷 P6305
    JSOI2020 酱油记
    洛谷 P6234
    CodeForces 1334F
  • 原文地址:https://www.cnblogs.com/xiaokang01/p/12505122.html
Copyright © 2011-2022 走看看