剑指offer-面试题40:最小的K个数

题目描述

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

参考方法 面试题39:数组中出现次数超过一半的数字

解法一:

时间复杂度O(nlogn)

  1. 先按照从小到大的顺序快速排序。
  2. 输出前K个数字。
class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int>v;
        if(input.size() <= 0 || k <= 0 || k >input.size())
            return v;
        QuickSort(input, 0, input.size()-1); // 快速排序
        for(int i=0; i<k; i++)
            v.push_back(input[i]);
        return v;
    }
    
    void QuickSort(vector<int>& input, int left, int right)
    {
        if(left < right)
        {
            int pivot = partition(input, left, right);
            QuickSort(input, left, pivot-1);
            QuickSort(input, pivot+1, right);
        }
    }
    
    int partition(vector<int>& input, int left, int right)
    {
        int i= left, j = right;
        while(i < j)
        {
            while(i < j && input[j] > input[left])
                j--;
            while(i < j && input[i] <= input[left])
                i++;
            swap(input[i], input[j]);
        }
        swap(input[i], input[left]);
        return i;
    }
};

解法一的简化版:

使用C++ 的 STL库的 sort 函数。

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

如果是在面试中碰到这些题目,上面的解法是远远不够的,因为面试官不爽,哈哈。

解法二:时间复杂度为O(n)的算法,只有当我们可以修改输入的数组时可用。

基于partition函数。

  1. 每次使用partition函数划分数组,选出基准数的位置。
  2. 如果选择的基准数的位置 pivot 小于 k-1,则在区间【pivot+1,right】继续划分。
  3. 如果选择的基准数的位置 pivot 大于 k-1,则在区间【left,pivot-1】继续划分。
  4. 循环2,3步,直到划分的基准数的位置等于 K-1 。
class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int>v;
        if(input.size() <= 0 || k <= 0 || k >input.size())
            return v;
        int left = 0, right = input.size()-1;
        int pivot = partition(input, 0, input.size()-1);
        while(pivot != k-1)
        {
            if(pivot < k-1)
            {
                left = pivot + 1;
                pivot = partition(input, left, right);
            }
            else
            {
                right = pivot - 1;
                pivot = partition(input, left, right);
            }
        }
        
        for(int i=0; i<k; i++)
            v.push_back(input[i]);
        return v;
    }
    
    
    int partition(vector<int>& input, int left, int right)
    {
        int i= left, j = right;
        while(i < j)
        {
            while(i < j && input[j] > input[left])
                j--;
            while(i < j && input[i] <= input[left])
                i++;
            swap(input[i], input[j]);
        }
        swap(input[i], input[left]);
        return i;
    }
};

解法三:时间复杂度为O(nlogk)的算法,特别适合处理海量数据

使用C++ 的 STL 中的multiset。

  1. 设置容器的尺寸为k。
  2. 顺序读取数组,如果容器没有满,则将数放入容器中,
  3. 如果满了,则在容器中找到最大值,如果当前遍历的数小于容器中的最大值,则先删除容器的最大值,再将数放入容器中。
  4. 如果大于容器中的最大值,最继续遍历下一个数。
  5. 最后遍历完后,返回容器中的数即可。
class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int>v;
        if(input.size() <= 0 || k <= 0 || k >input.size())
            return v;
        multiset<int, greater<int>>mul;
        mul.clear();
        for(int i=0; i<input.size(); i++)
        {
            if(mul.size() < k)
            {
                mul.insert(input[i]);
            }
            else
            {
                if(input[i] < *mul.begin())
                {
                    mul.erase(*mul.begin());
                    mul.insert(input[i]);
                }
            }
        }
        multiset<int, greater<int>>::iterator it = mul.begin();
        for(it = mul.begin(); it != mul.end(); it++)
            v.push_back(*it);
        return v;
    }
    
};

猜你喜欢

转载自blog.csdn.net/wchzh2015/article/details/88843193
今日推荐