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

本文介绍了一种算法问题——从给定的整数数组中找出最小的K个数,并提供了三种解决方案,包括快速排序法、基于partition的线性时间复杂度算法及利用优先队列实现的高效算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

输入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;
    }
    
};

或者使用优先队列 priority_queue ,也是堆的应用,

class Solution {
public:
    vector<int> getLeastNumbers_Solution(vector<int> input, int k) {
        vector<int>value;
        if(input.size() <=0 || k<=0 || k > input.size())
            return value;
        
        priority_queue<int, vector<int>, less<int> >q;
        
        for(int i=0; i<input.size(); i++)
        {
            if(q.size() < k)
            {
                q.push(input[i]);
            }
            else
            {
                if(q.top() > input[i])
                {
                    q.pop();
                    q.push(input[i]);
                }
            }
        }
        while(!q.empty())
        {
            value.push_back(q.top());
            q.pop();
        }
        reverse(value.begin(), value.end());
        return value;
        
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值