第40题:最小的K个数

第40题:最小的K个数

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

示例1

输入:[4,5,1,6,2,7,3,8],4
返回值:[1,2,3,4]

实现思路

方法一:直接采用排序的方式,调用STL中sort 方法

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> ret;
        if (k==0 || k>input.size()) return ret;
        sort(input.begin(), input.end());
        return vector<int>(input.begin(), input.begin()+k);  
    }
};

时间复杂度:O(nlongn)
空间复杂度:O(1)

方法二:利用快速排序的方法实现。

实现原理:基于数组的第K个数字来调整,使得比K个数字小的所有数字都位于数组的左边,比第K个数字大的所有数字都位于数组的右边,经过这样的调整后,位于数组中左边的K个数字就是最小的K个数字。

class Solution {
public:
    int partition(vector<int>& array, int low, int high)
    {
        int piv = array[low];
        while (low < high) {
            while ((low < high) && (array[high] >= piv)) {
                high--;
            }
            array[low] = array[high];

            while ((low < high) && (array[low] <= piv)) {
                low++;
            }
            array[high] = array[low];
        }
        array[low] = piv;
        return low;
    }
    
    void quickSort(vector<int>& input, int low, int high, int k)
    {
        int pivot = partition(input, low, high);
        
        if (pivot == k) {
            return;
        }
        else if (pivot > k) {
            quickSort(input, 0, pivot-1, k);
        }
        else {
            quickSort(input, pivot+1, high, k);
        }
    }
    
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
    {
        vector<int> ret;
        if (k == 0 || k > input.size()) {
            return ret;
        }
        int low = 0;
        int high = input.size() - 1;
        quickSort(input, low, high, k);
        for (int i=0; i<k; i++){
            ret.push_back(input[i]);
        }
        return ret;
    }
};

时间复杂度为: O ( n ) \Omicron(n) O(n) 每次partition的大小为n+n/2+n/4+... = 2n,最坏时间复杂度为 O(n^2), 因为每次partition都只减少一个元素

空间复杂度: O ( 1 ) \Omicron(1) O(1)

方法三:最大堆实现利用

实现原理:先把前 k 个数据建立一个大根堆,然后对后面的 length-k 个数依次遍历,如果当前数值小于堆顶的值时,则替换堆顶的值,然后对大根堆做向下调整。

class Solution {
public:
    void adjustHeap(vector<int>& input, int i, int length) 
    {
        int left = 2 * i + 1;  // i节点的左孩子,i从 0 开始
        int right = 2 * i + 2; // i节点的右孩子
        int max = i;           // 先设置父节点和子节点三个节点中最大值的位置为父节点下标
        if (left < length && input[left] > input[max]) {
            max = left;
        }
        if (right < length && input[right] > input[max]) {
            max = right;
        }
        
        //最大值不是父节点,则进行交换
        if (max != i) {
            int temp;
            temp = input[i];
            input[i] = input[max];
            input[max] = temp;
            adjustHeap(input, max, length); //递归调用,保证子树也是最大堆
        }
    }

    vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
    {
        if (input.empty() || k == 0 || k > input.size()) {
            return vector<int>{};
        }

        vector<int> result;
        //建立堆
        for (int i = input.size() / 2 - 1; i >= 0; i--) {
            adjustHeap(input, i, k); //堆的大小为k
        }
        //将后面的数依次和K个数的最大值比较
        for (int i = k; i < input.size(); i++) {
            if (input[0] > input[i]) {
                int temp = input[i];
                input[i] = input[0];
                input[0] = temp;
                adjustHeap(input, 0, k);
            }
        }
        for (int i = 0; i < k; i++) {
            result.push_back(input[i]);
        }
        return result;
    }
};

时间复杂度:O(nlongk), 插入容量为k的大根堆时间复杂度为O(longk), 一共遍历n个元素
空间复杂度:O(k)

方法比较

当K数值比较小时,可采用快速排序;当原数组中的数据顺序不可修改,且K数值很大时(海量数据),采用快速排序可能会占满内存,效率不高。此时使用最大堆数据结构实现最好。

猜你喜欢

转载自blog.csdn.net/breadheart/article/details/112597238
今日推荐