输入N个整数,寻找其中最小的k个数。
方法1:利用Partition函数,找到位于第k-1坐标的数,则它左边的数以及它自己就是要返回的k个数。
class Solution {
public:
void swap(int &fir, int &sec)
{
int temp = fir;
fir = sec;
sec = temp;
}
int getPartition(vector<int> & numbers, int start, int end) {
//int index = rand()%(end-start+1)+start;
//swap(numbers[index], numbers[end]);
int small = start - 1;
for (int index = start; index<end; ++index) {
if (numbers[index]<numbers[end]) {
++small;
if (small != index) {
swap(numbers[index], numbers[small]);
}
}
}
++small;
swap(numbers[small], numbers[end]);
return small;
}
vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
{
vector<int> result;
if (input.empty() || k>input.size() || k <= 0) return result;
int start = 0;
int end = input.size() - 1;
int index = getPartition(input, start, end);
while (index != (k - 1))
{
if (index > (k - 1))
{
end = index - 1;
index = getPartition(input, start, end);
}
else
{
start = index + 1;
index = getPartition(input, start, end);
}
}
for (int i = 0; i<k; ++i)
{
result.push_back(input[i]);
}
return result;
}
};
该方法的时间复杂度为O(n),该方法的缺点是会修改原有数组,并且在输入数据量十分大的时候,可能不能一次读入内存。
注意因为在Partition的过程中要修改原有数组,所以getPartition函数要传入vector的引用。
方法二:
基于最小堆(红黑树)的方法。
我们基于最小堆来实现,我们可以以O(1)的时间获得k个数字中的最大值,但需要O(logk)时间完成删除及插入操作。
我们用C++模板中的multiset完成,multiset本质是由红黑树实现的。
#include<set>
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
multiset<int, greater<int>> leastNumbers;
vector<int> vc;
if(k>input.size())
return vc;
for (int i = 0; i<input.size(); i++) {
if (leastNumbers.size()<k)
leastNumbers.insert(input[i]);
else {
if (input[i]<*leastNumbers.begin()) {
leastNumbers.erase(leastNumbers.begin());
leastNumbers.insert(input[i]);
}
}
}
auto it = leastNumbers.begin();
for(;it!=leastNumbers.end();it++)
vc.push_back(*it);
return vc;
}
};
该方法的时间复杂度为O(nlogk),该方法的优点是不需要修改原有数组,并且十分适合实时处理数据,因为该方法不用一次读入所有数据。
方法三:自己建立堆
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int len=input.size();
if(len<=0||k>len||k<=0) return vector<int>();
vector<int> res(input.begin(),input.begin()+k);
//建堆
make_heap(res.begin(),res.end());
for(int i=k;i<len;i++)
{
if(input[i]<res[0])
{
//先pop,然后在容器中删除
pop_heap(res.begin(),res.end());
res.pop_back();
//先在容器中加入,再push
res.push_back(input[i]);
push_heap(res.begin(),res.end());
}
}
//使其从小到大输出
//sort_heap(res.begin(),res.end());
return res;
}
};
方法四:建立最小堆
其实这样做没意义,因为建立最小堆是遍历完所有数然后建立的,建立完以后再连续pop k次即可。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int len = input.size();
if (len <= 0 || k>len || k <= 0) return vector<int>();
vector<int> res;
auto cmp = [](const int x, const int y) { return x > y; };
//建堆
make_heap(input.begin(), input.end(),cmp);
for (int i = 0; i<k; i++) {
pop_heap(input.begin(), input.end(),cmp);
res.push_back(*(input.end() - 1));
input.pop_back();
}
return res;
}
};