O(N)划分法,注意这个方法会改变原数据(函数参数是引用的情况下)!当然也可以再定义一个新容器对其划分
要求前k小的数,只要执行快排划分,每次划分都会把数据分成大小两拨。直到某一次划分的中心点正好在k处,则左侧0~k-1的数字正好就是所求。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int n=input.size();
if(n==0 or k==0 or n<k){return {};}
int le=0,ri=n-1,mi;
while((mi=partition(input,le,ri))!=k){//还没划分到k位置,接着划分
if(mi>k){
ri=mi-1;
}
else{
le=mi+1;
}
}
vector<int>res;
for(int i=0;i<k;++i){
res.push_back(input[i]);
}
return res;
}
//算法导论快排的划分算法
int partition(vector<int>& nums,int le,int ri){
if(le>=ri){return le;}
int stable=nums[ri];
int i=le-1,j=le;
while(j<ri){
if(nums[j]<stable){
swap(nums[++i],nums[j]);
}
++j;
}
swap(nums[i+1],nums[ri]);
return i+1;
}
};
O(N logK)堆排序法,这个方法特别适合海量数据,因为所有操作都在k大小的容器内进行!
要求最小的k个数,那么先在堆中放置k个数并建立最大堆,对于之后考察的每个数字x,如果x比堆里最大(也就是堆顶,因为是最大堆)更小,说明当前堆顶肯定不在最后的解中,所以把堆顶pop掉,并push当前x,再维护最大堆性质,接下来以此类推。最后剩下的堆就是所有数据里最小的k个。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int n=input.size();
if(k==0 or n==0 or k>n){return {};}
vector<int> heap(k,0);
for(int i=0;i<k;++i){
heap[i]=input[i];
}
make_heap(heap.begin(),heap.end());//默认就是大顶堆
for(int i=k;i<n;++i){
if(heap[0]>input[i]){
pop_heap(heap.begin(),heap.end());
heap.back()=input[i];
push_heap(heap.begin(),heap.end());
}
}
return heap;
}
};