输入整数数组 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
借助此题,顺便复习下排序算法
快排
开始时,flag这里出了问题,应该是记录最左端的这个数本身,写成了记录其下标
下面是将数组快排后,返回前K 个元素(其实不用)
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
if(k < 1)
return vector<int> ();
fast_sort(arr, 0, arr.size() - 1);
vector<int> res(k);
for(int i = 0; i < k; ++i)
res[i] = arr[i];
return res;
}
private:
void fast_sort(vector<int>& arr, int left, int right){
if(left >= right)
return;
int flag = arr[left];
int l = left, r = right;
while(l < r){
while(l < r && arr[r] >= flag)
--r;
arr[l] = arr[r];
while(l < r && arr[l] < flag)
++l;
arr[r] = arr[l];
}
arr[l] = flag;
fast_sort(arr, left, l - 1);
fast_sort(arr, l + 1, right);
}
};
(星标思想)借助快排,找到数组中的第K小的元素,该元素左面的就是结果
注意:像寻找数组中的第k小元素,都用快速选择来处理,类似于快排
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
if(k < 1)
return vector<int> ();
partition(arr, 0, arr.size() - 1, k - 1);//注意这里是下标k-1
vector<int> res(k);
for(int i = 0; i < k; ++i)
res[i] = arr[i];
return res;
}
private:
void partition(vector<int>& arr, int left, int right, int k){
int p = fast_sort(arr, left, right);
if(p == k)//此时前k个元素是前k小的元素
return;
else if(p > k){
//说明第k小的元素在[left, p)
partition(arr, left, p - 1, k);
}
else{
//说明第k小的元素在(p,right]
partition(arr, p + 1, right, k);
}
}
int fast_sort(vector<int>& arr, int left, int right){
int flag = arr[left];
int l = left, r = right;
while(l < r){
while(l < r && arr[r] >= flag)
--r;
arr[l] = arr[r];
while(l < r && arr[l] < flag)
++l;
arr[r] = arr[l];
}
arr[l] = flag;
return l;
}
};
归并排序
结果:超时了,通过了33/38
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
if(k < 1)
return vector<int> ();
vector<int> temp(arr);
merge_sort(arr, temp, 0, arr.size() - 1);
vector<int> res(k);
for(int i = 0; i < k; ++i)
res[i] = arr[i];
return res;
}
private:
void merge_sort(vector<int>& arr, vector<int> temp, int left, int right){
if(left >= right)
return;
int mid = (left + right) >> 1;
merge_sort(arr, temp, left, mid);
merge_sort(arr, temp, mid + 1, right);
int i = mid, j = right, k = right;
while(i >= left && j >= mid + 1){
if(arr[i] > arr[j]){
temp[k--] = arr[i--];
}
else{
temp[k--] = arr[j--];
}
}
while(i >= left){
temp[k--] = arr[i--];
}
while(j >= mid + 1){
temp[k--] = arr[j--];
}
++k;
while(k <= right){
arr[k] = temp[k];
++k;
}
}
};
借助大根堆
默认情况下,c++中的priority_queue是大根堆实现的,也就是队列中的元素是降序排列的
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
if(k < 1)
return vector<int> ();
vector<int> res;
priority_queue<int> q;
//1.先将前k个元素入队
for(int i = 0; i < k; ++i){
q.push(arr[i]);
}
//2.判断后续的元素,如果小于队头元素,则将队头元素更新为该元素
for(; k < arr.size(); ++k){
if(arr[k] < q.top()){
q.pop();
q.push(arr[k]);
}
}
//3.将队列中的元素存入vector
while(!q.empty()){
res.push_back(q.top());
q.pop();
}
return res;
}
};