题目:
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处
解题思路:
- 直接排序,获取数组v[k]值。
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int>re(k,0);
if(arr.size()<k)return re;
sort(arr.begin(),arr.end());
for(int i=0;i<k;i++){
re[i]=arr[i];
}
return re;
}
};
- 快速排序改为快速选择排序。其实理解一下,这道题就是求中位数的O(n)方法,求第k个数,求前k个数字。而快排其实就是在pivot前面的数组绝对小于pivot后面的数字,然后依次划分到最小单位求得全排序。这里将pivot好好设置一下,就可以得到一种新的性能十分优越的方法。
class Solution {
private:
vector<int>re;
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
if(arr.size()<=k)return arr;
if(k<=0)return re;
quicksort(arr,0,arr.size()-1,k);
return re;
}
void quicksort(vector<int>&arr,int low1,int high1,int k){
int i=0,j=0,low=low1,high=high1,st=low,ed=high;
int pivot=arr[low];
while(low<high){
while(low<high&&arr[high]>=pivot)high--;
arr[low]=arr[high];
while(low<high&&arr[low]<pivot)low++;
arr[high]=arr[low];
}
arr[high]=pivot;
if(low==k){
for(i=0;i<k;i++){
re.push_back(arr[i]);
}
return;
}else{
if(low>k){
quicksort(arr,st,low-1,k);
}else{
quicksort(arr,low+1,ed,k);
}
}
}
};
- 小顶堆,堆排序一下的事情。后来发现构建所有数组的小顶堆时间消耗和方法一差不多。既然如此,构建大小为k的小顶堆可不可行呢?可行,但是每次插入新元素的话,很难确定是不是k小范围内的,好吧,找k小的最大值太麻烦了,后来改成大顶堆了,这样下来时间代价就小多了,假设每次都要调整一下的话,时间大约也不过O(k)+O((n-k)*logk),时间代价小多了。另外,这次是牛客网上的边界条件比LeetCodes上的测试更细,LeetCode这次合题意的边界情况也有一个没有考虑,就是size==k情况的处理,所以按照牛客网上的条件修改吧。修改版本见最后一个代码。
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
buildheap(arr);
vector<int>re;
int size=arr.size();
for(int i=0;i<k;i++){
re.push_back(arr[0]);
int tmp=arr[0];
arr[0]=arr[size-1];
arr[size-1]=tmp;
size--;
AdjustUp(arr,0,size-1);
}
return re;
}
void buildheap(vector<int>&arr){
int len=arr.size();
for(int i=len/2;i>=0;i--){
AdjustUp(arr,i,len-1);
}
}
void AdjustUp(vector<int>&arr,int st,int ed){
int i=st;
int k=st*2;
int stnum=arr[st];
while(k<=ed){
if((k+1)<=ed&&arr[k]>arr[k+1]){
k++;
}
if(stnum>arr[k]){
arr[i]=arr[k];
i=k;
k=2*k;
}else{
arr[i]=stnum;
break;
}
}
arr[i]=stnum;
return ;
}
};
时间和方法一居然差不多,不过也正常,调整一下。
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int>re;
if(arr.size()<k){
return re;
}
if(arr.size()==k){
for(int i=0;i<k;i++){
re.push_back(arr[i]);
}
return re;
}
for(int i=k/2;i>=0;i--){
AdjustDown(arr,i,k-1);
}
int size=arr.size();
for(int i=k;i<size;i++){
if(arr[i]<arr[0]){
int tmp=arr[0];
arr[0]=arr[i];
arr[i]=tmp;
AdjustDown(arr,0,k-1);
}
}
for(int i=0;i<k;i++){
re.push_back(arr[i]);
}
return re;
}
void AdjustDown(vector<int>&arr,int st,int ed){
int i=st;
int k=st*2;
int stnum=arr[st];
while(k<=ed){
if((k+1)<=ed&&arr[k]<arr[k+1]){
k++;
}
if(stnum<arr[k]){
arr[i]=arr[k];
i=k;
k=2*k;
}else{
arr[i]=stnum;
break;
}
}
arr[i]=stnum;
return ;
}
};