最小的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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM