输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
方法一:基于快排的Partition,时间复杂度O(n)
解析:基于数组的第k个数字来调整,则使得比第k个数字小的所有数字都位于数组的左边,比第个数字大的所有数字都位于数组的右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字(这k个数字不一定是排序的).
class Solution {
public:
int partition(vector<int> &vec,int low,int high){
if(vec.size() == 0)
return 0;
int temp = vec[low],i=low,j=high;
while(i<j){
while(i<j && vec[j]>temp)
j--;
if(i<j){
vec[i] = vec[j];
i++;
}
while(i<j && vec[i]<temp)
i++;
if(i<j){
vec[j] = vec[i];
j--;
}
}
vec[i] = temp;
return i;
}
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> ans;
if(input.size()==0 || k==0 || k>input.size())
return ans;
int low = 0,high = input.size()-1;
int index = partition(input,low,high);
while(index != k-1){
if(index > k-1)
high = index-1;
else
low = index+1;
index = partition(input,low,high);
}
for(int i=0;i<k;i++)
ans.push_back(input[i]);
return ans;
}
};
方法二堆排:时间复杂度O(nlogk)
基于“先整体排序,然后取前k个元素”的思路引申:需要的是前k小的数,没必要把整个数组都排好序。这样一来,时间复杂度可以降到O(nLogk)。利用最大堆排,只不过在这里用的是最小堆算法
class Solution {
public:
void heapAdjust(vector<int> &vec,int low,int high){
int i=low,j=2*i;
int temp = vec[i];
while(j<=high){
while(j<high && vec[j]>vec[j+1])
j++;
if(vec[j] < temp){
vec[i] = vec[j];
i=j;
j=2*i;
}else
break;
}
vec[i] = temp;
}
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> ans;
if(input.size()==0 || k <=0 || k>input.size())
return ans;
input.insert(input.begin(),0);//将下标变为从1开始
int len = input.size()-1;
for(int i=len/2;i>=1;i--)
heapAdjust(input,i,len);
for(int i=len,j=0;i>=1;i--,j++){
if(j==k)
break;
swap(input[1],input[i]);
ans.push_back(input[i]);
heapAdjust(input,1,i-1);
}
return ans;
}
};