剑指offer 40 最小的K个数

题目描述

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

思路:

1、第一个思路肯定是通过排序,之后返回前k个数即可,时间复杂度O(nlogn);

2、利用Partition 的思想。找出划分位置index,index 前的数均比它小,index后的数均比它大。比较index与k-1的大小,决定下次划分的区间。当index==k-1时,那么0~index之间的数就是要求的数,时间复杂度O(n)

但这种方法需要修改输入的数组,若面试时要求可以修改,则可以用此方法

代码:牛客超时

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int n=input.size();
        int start=0;
        int end=n-1;
        vector<int>output;
        if(k>n||k<0||n==0)
        return output;
        int index=Partition(input,start,end);
        while(index!=k-1)
    {
        if(index>k-1)
        {end=index-1;
          index=Partition(input,start,end);}
        else 
        { start=index+1;
        index=Partition(input,start,end);}
    }
           
         for(int i=0;i<k;i++)
         output.push_back(input[i]);
         return output;
            
    }
    int Partition(vector<int>A,int left,int right)
    {
              int pivort=A[right];
              int tail=left-1;
              for(int i=left;i<=right;i++)
              {
              if(pivort>A[i])
              {
                 tail++;
                  if(tail!=i)
                  {
                      int temp=A[tail];
                      A[tail]=A[i];
                      A[i]=temp;
                  }
              }
            }
         return tail;
    }
};

3、使用基于二叉树的容器容器,创建一个大小为K的数据容器来存储最小的k个数字

  • 可以先创建一个大小为k的数据容器来存储最小的k个数字,从输入的n个整数中一个一个读入放入该容器中,如果容器中的数字少于k个,按题目要求直接返回空;
  • 如果容器中已有k个数字,而数组中还有值未加入,此时就不能直接插入了,而需要替换容器中的值。按以下步骤进行插入: 
    1. 先找到容器中的最大值;
    2. 将待查入值和最大值比较,如果待查入值大于容器中的最大值,则直接舍弃这个待查入值即可;如果待查入值小于容器中的最小值,则用这个待查入值替换掉容器中的最大值;
    3. 重复上述步骤,容器中最后就是整个数组的最小k个数字。

使用set或multiset

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int>input, int k) {
int len=input.size();
        if(len<=0||k>len) return vector<int>();
         
        //仿函数中的greater<T>模板,从大到小排序
        multiset<int, greater<int> > leastNums;
        vector<int>::iterator vec_it=input.begin();
        for(;vec_it!=input.end();vec_it++)
        {
            //将前k个元素插入集合
            if(leastNums.size()<k)
                leastNums.insert(*vec_it);
            else
            {
                //第一个元素是最大值
                multiset<int, greater<int> >::iterator greatest_it=leastNums.begin();
                //如果后续元素<第一个元素,删除第一个,加入当前元素
                if(*vec_it<*(leastNums.begin()))
                {
                    leastNums.erase(greatest_it);
                    leastNums.insert(*vec_it);
                }
            }
        }
         
        return vector<int>(leastNums.begin(),leastNums.end());
    }
};

此处用less<int>,greatest_it=leastNums.end()

为什么会出错????


使用最大堆

在最大堆中,根结点的值总是大于它的子树中任意结点的值,可以在O(1)的时间内得到已有的K个数字中的最大值,但需要O(logk)时间完成删除及插入操作。

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int>input, int k) {
        vector<int> result;
        if(input.size()==0||k==0||k>input.size()){
            return result;
        }
         for(int i=k/2-1;i>=0;i--){//初始化堆
             
            adjustHeap(input,i,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;
    }
    void adjustHeap(vector<int>&input,int i,int length){//堆调整
         
        int child=i*2+1;
        if(child<length){
             
            if(child+1<length&&input[child+1]>input[child]){
                child=child+1;
            }
            if(input[child]>input[i]){
                int temp=input[i];
                input[i]=input[child];
                input[child]=temp;
            adjustHeap(input,child,length);
            }
        }
    }
};
 

 优缺点比较:

总结:
当需要在某个数据容器内频繁查找以及替换最大值时,要想到二叉树是很好的选择,并能想到用堆或者红黑树等特殊的二叉树来实现。

猜你喜欢

转载自blog.csdn.net/weixin_41413441/article/details/80632568