题目要求
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
题目分析
坑点:输入n个整数,找出其中最小的K个数
在这里我们很容易在主观上默认n>k,从而在讨论k的不合法性时,忘记了k>n的情况,实际上当 k>n 或者 k<=0 那么都将返回空!!!
下面我们从两种解法来讨论本题的做法
第一种,时间复杂O(n),对于一个排序的数组,我们只要输出他的前K个数字即可符合题意。
所以我们第一种做法是对数组进行排序,在这里可以有多种排序的方法,就不过多赘述了,不同的放法对应的效率不同。这里为了方便,我们使用stl里的排序函数进行排序。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> result;
if(input.size() == 0 || k<=0 || k>input.size()) // 输入不合法的情况
return result;
sort(input.begin(),input.end());
// k不合法 <0 ; k>size? 那么输出空
for(int i=0;i<k;++i)
{
result.push_back(input[i]);
}
return result;
}
};
第二种,我们用最大堆来实现,主要考虑在数据流较大时候的效率和可操作性。
思想是,我们先把数组中的前k个数保存起来,接下来只要依次比较后边的数,如果后面的数比k个数中最大的还大那么不予考虑,如果比最大的小那么就进行替换,所以我们还要知道k个书中最大的是那个,根据这个需要,我们需用从大到小排列顺序的multieset作为结构。k个数中的最大值就是multiset的首元素!
简化为为一个关系就是:插入—比较—替换(或不变)
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
{
vector<int> result;
int len = input.size();
if(input.empty() || k<=0 || len < k) return result;
multiset<int, greater<int> > leastNumbers; // 从大到小排序
multiset<int, greater<int> >::iterator iterGreater; // 定义迭代器
vector<int>::iterator iter = input.begin();
for(; iter != input.end(); ++iter)
{
// 将前k个数直接插入进multiset中,注意是小于K,取等号的话会多出一个数字
if(leastNumbers.size() < k)
{
leastNumbers.insert(*iter);
}
else
{
// 因为设置的从大到小排序,故multiset中第一个位置的元素即为最大值
iterGreater = leastNumbers.begin();
// 如果input中当前元素比multiset中最大元素小,则替换;即保持multiset中这k个元素是最小的。
if(*iter < *(leastNumbers.begin()))
{
// 替换掉当前最大值
leastNumbers.erase(iterGreater);
leastNumbers.insert(*iter);
}
}
}
for(iterGreater = leastNumbers.begin();iterGreater!=leastNumbers.end();++iterGreater)
{
result.push_back(*iterGreater); // 将multiset中这k个元素输出
}
return result;
}
};