題目:
輸入整數數組 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 ;
}
};