面试题40:最小的K个数

题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
方法一:不修改原数组,时间复杂度O(NlgK)

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> result;
        int length = input.size();
        if(length <= 0 || k <= 0 || k > length)
            return result;
        for(int i = 0; i < input.size(); i++)
        {
            if(result.size() < k)
                result.push_back(input[i]);
            else
            {
                for(int j = k / 2; j >= 0; j--)
                    HeadAdjust(result, j, k);
                for(int j = k - 1; j > 0; j--)//heapsrot
                {
                    swap(result[0], result[j]);
                    HeadAdjust(result, 0, j);
                }
                if(result[k-1] > input[i])
                    result[k-1] = input[i];
            }
        }
        return result;
    }
private:
    void HeadAdjust(vector<int> &input, int parent, int length){
        int temp = input[parent];
        int child = 2 * parent + 1;
        while(child < length){
            if(child + 1 < length && input[child] < input[child+1]){
                child++;
            }
            if(temp >= input[child]){
                break;
            }
            input[parent] = input[child];
            parent = child;
            child = 2 * parent + 1;
        }
        input[parent] = temp;
    }
};

方法二:变动原数组,时间复杂度O(NlgK)

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> res;
        if(input.empty() || k <= 0 || k > input.size())
            return res;
        int len = input.size();
        for(int i = k/2 - 1; i >= 0; --i)
        {
            sift(input,i,k-1);//建立初始大根堆;
        }
        for(int j = k; j < len; ++j)//从第k个元素开始与小根堆的根节点比较
        {                           //0~k-1的元素已成堆
            if(input[j] < input[0])
            {
                int temp = input[0];
                input[0] = input[j];
                input[j] = temp;
                sift(input,0,k-1);//调整堆
            }
        }
        for(int i = 0; i < k; ++i)
            res.push_back(input[i]);
        return res;
    }

    void sift(vector<int> &input, int low, int high)//需要修改input,用引用
    {
        int i = low;
        int j = 2*i + 1;//注意下标更新,从0开始需加1
        int tmp = input[low];
        while(j <= high)
        {
            if(j+1 < high && input[j] < input[j+1])
                j++;
            if(tmp < input[j])
            {
                input[i] = input[j];
                i = j;//修改i,j的值,以便继续向下筛选
                j = 2*i + 1;//
            }
            else
                break;
        }
        input[i] = tmp;//被筛选的节点放入最终位置
    }
};

你可能感兴趣的:(剑指Offer)