题目描述
输入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个数字,而数组中还有值未加入,此时就不能直接插入了,而需要替换容器中的值。按以下步骤进行插入:
- 先找到容器中的最大值;
- 将待查入值和最大值比较,如果待查入值大于容器中的最大值,则直接舍弃这个待查入值即可;如果待查入值小于容器中的最小值,则用这个待查入值替换掉容器中的最大值;
- 重复上述步骤,容器中最后就是整个数组的最小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); } } } };
优缺点比较:
总结:
当需要在某个数据容器内频繁查找以及替换最大值时,要想到二叉树是很好的选择,并能想到用堆或者红黑树等特殊的二叉树来实现。