题目
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
思路
1、(array被改变了)结合数组-4的第一种类似快排partion的思想。最小的k个数,那么找到第k个数,其左边就是最小的k个数 (不是有序的),所以时间复杂度是O(N), 快排的结果是base两边都是有序的,时间复杂度是O(NlogN)。
快排是对base两边都递归下去,这个是只判断一边。
2、(array未被改变)先创建一个大小为k的数据容器来存储最小的k个数字,接下来我们每次从输入的n个整数中的n个整数中读入一个数。如果容器中已有的数字少于k个,则直接把这次读入的整数放入容器之中;如果容器已经有k个数字了,也就是容器满了,此时我们不能再插入新的数字而只能替换已有的数字。找出这已有的k个数中的最大值,然后拿这次待插入的整数和最大值进行比较。如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还要大,那么这个数不可能是最小的k个整数之一,于是我们可以抛弃这个整数。
因此当容器满了之后,我们要做3件事情:一是在k个整数中找到最大数;二是有可能在这个容器中删除最大数;三是有可能要插入一个新的数字。如果用一个二叉树来实现这个数据容器,那么我们在O(logk)时间内实现这三步操作。因此对于n个输入数字而言,总的时间效率就是O(nlogk)
可以建立大根堆来实现
make_heap 将[start, end)范围进行堆排序,默认使用less, 即最大元素放在第一个。
pop_heap 将front(即第一个最大元素)移动到end的前部,同时将剩下的元素重新构造成(堆排序)一个新的heap。
push_heap 对刚插入的(尾部)元素做堆排序。
sort_heap 将一个堆做排序,最终成为一个有序的系列,可以看到sort_heap时,必须先是一个堆(两个特性:1、最大元素在第一个 2、添加或者删除元素以对数时间,因此必须先做一次make_heap.
3、直接使用红黑树来实现,选用multiset,允许集合内数字重复。 O(NlogK)
#include <iostream>
#include <vector>
using namespace std;
class Solution
{
public:
vector<int> minKnumber(vector<int> &array, int k)
{
vector<int> result;
int len = array.size();
if (len == 0 || k <= 0 || k > len)
return result;
int start = 0;
int end = len - 1;
int index = partion(array, start, end);
while (index != k - 1)
{
if (index > k - 1)
index = partion(array, start, index - 1);
else
index = partion(array, index + 1, end);
}
for (int i = 0; i < k; i++)
{
result.push_back(array[i]);
}
return result;
}
private:
int partion(vector<int> &array, int left, int right)
{
int baseNum = array[left];
while (left < right)
{
while (left < right && array[right] >= baseNum)
right--;
array[left] = array[right];
while (left < right && array[left] <= baseNum)
left++;
array[right] = array[left];
}
array[left] = baseNum;
return left;
}
};
int main()
{
Solution s;
vector<int> array{4, 5, 1, 6, 2, 7, 3, 8};
vector<int> result = s.minKnumber(array, 1);
for (auto i : result)
cout << i;
cout << endl;
system("pause");
return 0;
}
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution
{
public:
vector<int> getLeastNumber(const vector<int> array, int k)
{
int len = array.size();
if (len <= 0 || k <= 0 || k > len)
return vector<int>();
vector<int> result(array.begin(), array.begin() + k);
make_heap(result.begin(), result.end()); //建堆,将前 k 个数存在result中,默认大根堆
for (int i = k; i < len; i++)
{
if (array[i] < result[0]) //如果有元素比堆中最大的都大
{
pop_heap(result.begin(), result.end()); //先把堆中最大的移到最后面,然后再pop出去
result.pop_back();
result.push_back(array[i]); //将新的元素push进来,再调整堆
push_heap(result.begin(), result.end());
}
}
sort(result.begin(), result.end()); //对堆排序,使其从小到大输出
return result;
}
};
#include <iostream>
#include <set>
#include <vector>
#include <functional>
using namespace std;
class Solution
{
public:
//不改变原始数组,用红黑树的multiset实现
vector<int> getLeastNumbers( vector<int> &array, int k)
{
vector<int> result;
int len = array.size();
if (len <= 0 || k <= 0 || k > len)
return result;
multiset<int, greater<int> > leastNumber;
vector<int>::iterator vec_it = array.begin();
for (; vec_it != array.end(); vec_it++)
{
if (leastNumber.size() < k)
leastNumber.insert(*vec_it);
else
{
multiset<int, greater<int>>::iterator great_it = leastNumber.begin();
if (*vec_it < *great_it)
{
leastNumber.erase(*great_it);
leastNumber.insert(*vec_it);
}
}
}
return vector<int>(leastNumber.begin(), leastNumber.end());
}
};
int main()
{
Solution s;
vector<int> array{2, 3, 2, 4, 2, 9, 7, 4};
vector<int> result = s.getLeastNumbers(array, 6);
for (auto i : result)
cout << i;
cout << endl;
system("pause");
return 0;
}