40.最小的K个数
1.题目的描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
2.方法1(最大堆)
最大堆实现,当堆小于K时,依次插入数字,当堆大于K时,待插入的数字与堆顶比较,如果小于则插入,否则不插入。
3.代码
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> result;
if(input.empty() || k <= 0 || k>input.size())
return result;
multiset<int,greater<int>> setData;
for(int i =0;i < input.size();++i){
if(setData.size() < k){
setData.insert(input[i]);
}
else{
multiset<int,greater<int>>::iterator max = setData.begin();
if(input[i] < *max){
setData.erase(max);
setData.insert(input[i]);
}
}
}
for(multiset<int,greater<int>>::iterator iter = setData.begin();iter != setData.end();++iter){
result.push_back(*iter);
}
return result;
}
};
4.复杂度分析
时间复杂度:O(N*logK)
空间复杂度:O(1)
5.方法2(partition)
采用快排的思想,通过partition把数组元素放到正确的位置index,如果index > k - 1,即index左边的数(都小于右边)大于k个,因此right = index - 1;如果index < k - 1,说明index左边的数(都小于右边)小于k个,因此left = index + 1;如果index == k - 1,说明找到了k个最小的数。最后把数组的前k个数放入结果数组。
6.代码
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int> res;
if(arr.empty() || k <= 0 || k > arr.size()){
return res;
}
int left = 0;
int right = arr.size() - 1;
int index = 0;
while(index != k - 1){
index = partition(arr, left, right);
if(index > k - 1){
right = index - 1;
}
else{
left = index + 1;
}
}
for(int i = 0;i < k;++i){
res.push_back(arr[i]);
}
return res;
}
int partition(vector<int>& arr, int left, int right){
int t = left;
for(int i = left;i < right; ++i){
if(arr[i] < arr[right]){
swap(arr[t++], arr[i]);
}
}
swap(arr[t], arr[right]);
return t;
}
};
7.复杂度分析
时间复杂度:O(N),partition操作的时间复杂度是O(N),每次执行的时间复杂度都比上一次小,加起来就是O(N)。
空间复杂度:O(1)