劍指 Offer——最小的 K 個數

1. 題目

2. 解答

2.1. 方法一——大頂堆

參考 堆和堆排序 以及 堆的應用,咱們將數組的前 K 個位置看成一個大頂堆。api

首先建堆,也即對堆中 [0, (K-2)/2] 的節點從上往下進行堆化。第 K/2 個節點如有子節點,其左子節點位置應該爲 2 * K/2 + 1 = K+1,而咱們堆中的最大位置爲 K-1,顯然第 K/2 個節點是第一個葉子節點,不用堆化。數組

建完堆以後,咱們順序訪問原數組 [k, n-1] 位置的元素,若是當前元素小於堆頂元素也就是位置爲 0 的元素,那麼刪除堆頂元素並將當前元素插入堆中。ui

最後,堆中的 K 個元素即爲所求。code

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        
        if (k > input.size())
        {
            vector<int> result;
            return result;
        }
        Build_Heap_K(input, k);
        vector<int> result(input.begin(), input.begin()+k);
        return result;
    }
    
    void Build_Heap_K(vector<int> &input, int k)
    {
        // input 的 [0, k-1] 做爲一個大小爲 K 的大頂堆
        // 而後從上往下進行堆化
        // 也就是對堆中 [0, (k-2)/2] 的節點進行堆化
        for (int i = (k-2)/2; i >= 0; i--)
            Heapify(input, k, i);
        
        // 遍歷 input 的 [k, n-1] 的元素
        // 若是某元素小於堆頂值,將其插入堆中
        // 也即將其替換爲堆頂元素,堆化之
        for (int i = k; i < input.size(); i++)
        {
            if (input[i] < input[0])
            {
                input[0] = input[i];
                Heapify(input, k, 0);
            }
        }
    }
    
    void Heapify(vector<int> &input, int k, int i)
    {
        while(1)
        {
            int max_pos = i;
            if (2*i+1 < k && input[2*i+1] > input[max_pos])
                max_pos = 2 * i + 1;
            if (2*i+2 < k && input[2*i+2] > input[max_pos])
                max_pos = 2 * i + 2;
            if (max_pos == i)
                   break;
            else
            {
                int temp = input[max_pos];
                input[max_pos] = input[i];
                input[i] = temp;
            }
            i = max_pos;
        }
    }
};
2.2. 方法二——快排分治

可參考 LeetCode 215——數組中的第 K 個最大元素blog

快排的時候須要分區,分區點左邊的元素都小於主元,分區點右邊的元素都大於主元。若是分區後主元的位置剛好爲 K,那左邊正好是最小的 K 個數;若是大於 K,咱們須要遞歸在左邊找到第 K 個位置;若是小於 K,咱們則須要遞歸在右邊找到第 K 個位置。排序

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int n = input.size();
        if (k > n)
        {
            vector<int> result;
            return result;
        }
        Quick_Sort(input, 0, n-1, k);
        vector<int> result(input.begin(), input.begin()+k);
        return result;
    }
    
    void Quick_Sort(vector<int> &input, int left, int right, int k)
    {
        if (left < right)
        {
            int pivot = input[right];
            int i = left;
            int j = left;
            
            for (; j < right; j++)
            {
                if (input[j] < pivot)
                {
                    int temp = input[i];
                    input[i] = input[j];
                    input[j] = temp;
                    i++;
                }
            }
            input[j] = input[i];
            input[i] = pivot;
            
            if (i == k)    return;
            else if (i > k)    Quick_Sort(input, left, i-1, k);
            else Quick_Sort(input, i+1, right, k);
        }
    }
};

獲取更多精彩,請關注「seniusen」!遞歸

相關文章
相關標籤/搜索