输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
解法一:排序后,取出前k个数。O(nlogn)。
代码略。
解法二:建立n个元素的最小堆,每次去除堆顶的最小值,然后弹出堆顶,重新构成最小堆。
O(klogn)
class Solution
{
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
{
vector<int> ret;
if (input.empty() || k > input.size())
return ret;
make_heap(input.begin(), input.end(), greater<int>());
for (int i = 0; i < k; i++)
{
pop_heap(input.begin(), input.end(), greater<int>());
ret.push_back(input.back());
input.pop_back();
}
return ret;
}
};
解法三:建立k个元素的最大堆(借助multiset来完成),遍历数组, (整个堆只有k个单元)
1、如果堆没有k个元素 或者 当前数组元素比堆顶小,那就把堆顶弹出,当前元素压入,重新构成堆
2、否则,遍历数组下一个元素
最后堆中的元素就是最小的k个数。
O(nlogk) 适合海量数据
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
{
vector<int> ret;
if (input.empty() || k > input.size())
return ret;
for (int i = 0; i < k; i++)
ret.push_back(input[i]);
make_heap(ret.begin(), ret.end(), less<int>());
for (int i = k; i < input.size(); i++)
{
if (input[i] < ret[0])
{
pop_heap(ret.begin(), ret.end(), less<int>());
ret.pop_back();
ret.push_back(input[i]);
push_heap(ret.begin(), ret.end(), less<int>());
}
}
return ret;
}
};
解法三:快排变种,每次遍历将数组分为两边。
O(n)
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
{
if (input.empty() || k > input.size())
return input;
int start = 0, end = input.size() - 1;
while (start < end)
{
int index = Partition(input, start, end);
if (index < k - 1)
start = index + 1;
else if (index > k - 1)
end = index;
else
break;
}
return vector<int> (input.begin(), input.begin() + k);
}
int Partition(vector<int>& input, int start, int end)
{
if (start >= end) return start;
int i = start, j = end;
int pivot = input[(end - start) / 2 + start];
while (i <= j)
{
while (i <= j && input[j] > pivot)
j--;
while (i <= j && input[i] < pivot)
i++;
if (i <= j)
swap(input[i++], input[j--]);
}
return (j >= start)? j : start;
}
};