题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
参考方法 面试题39:数组中出现次数超过一半的数字
解法一:
时间复杂度O(nlogn)
- 先按照从小到大的顺序快速排序。
- 输出前K个数字。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int>v;
if(input.size() <= 0 || k <= 0 || k >input.size())
return v;
QuickSort(input, 0, input.size()-1); // 快速排序
for(int i=0; i<k; i++)
v.push_back(input[i]);
return v;
}
void QuickSort(vector<int>& input, int left, int right)
{
if(left < right)
{
int pivot = partition(input, left, right);
QuickSort(input, left, pivot-1);
QuickSort(input, pivot+1, right);
}
}
int partition(vector<int>& input, int left, int right)
{
int i= left, j = right;
while(i < j)
{
while(i < j && input[j] > input[left])
j--;
while(i < j && input[i] <= input[left])
i++;
swap(input[i], input[j]);
}
swap(input[i], input[left]);
return i;
}
};
解法一的简化版:
使用C++ 的 STL库的 sort 函数。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int>v;
if(input.size() <= 0 || k <= 0 || k >input.size())
return v;
sort(input.begin(), input.end());
for(int i=0; i<k; i++)
v.push_back(input[i]);
return v;
}
};
如果是在面试中碰到这些题目,上面的解法是远远不够的,因为面试官不爽,哈哈。
解法二:时间复杂度为O(n)的算法,只有当我们可以修改输入的数组时可用。
基于partition函数。
- 每次使用partition函数划分数组,选出基准数的位置。
- 如果选择的基准数的位置 pivot 小于 k-1,则在区间【pivot+1,right】继续划分。
- 如果选择的基准数的位置 pivot 大于 k-1,则在区间【left,pivot-1】继续划分。
- 循环2,3步,直到划分的基准数的位置等于 K-1 。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int>v;
if(input.size() <= 0 || k <= 0 || k >input.size())
return v;
int left = 0, right = input.size()-1;
int pivot = partition(input, 0, input.size()-1);
while(pivot != k-1)
{
if(pivot < k-1)
{
left = pivot + 1;
pivot = partition(input, left, right);
}
else
{
right = pivot - 1;
pivot = partition(input, left, right);
}
}
for(int i=0; i<k; i++)
v.push_back(input[i]);
return v;
}
int partition(vector<int>& input, int left, int right)
{
int i= left, j = right;
while(i < j)
{
while(i < j && input[j] > input[left])
j--;
while(i < j && input[i] <= input[left])
i++;
swap(input[i], input[j]);
}
swap(input[i], input[left]);
return i;
}
};
解法三:时间复杂度为O(nlogk)的算法,特别适合处理海量数据
使用C++ 的 STL 中的multiset。
- 设置容器的尺寸为k。
- 顺序读取数组,如果容器没有满,则将数放入容器中,
- 如果满了,则在容器中找到最大值,如果当前遍历的数小于容器中的最大值,则先删除容器的最大值,再将数放入容器中。
- 如果大于容器中的最大值,最继续遍历下一个数。
- 最后遍历完后,返回容器中的数即可。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int>v;
if(input.size() <= 0 || k <= 0 || k >input.size())
return v;
multiset<int, greater<int>>mul;
mul.clear();
for(int i=0; i<input.size(); i++)
{
if(mul.size() < k)
{
mul.insert(input[i]);
}
else
{
if(input[i] < *mul.begin())
{
mul.erase(*mul.begin());
mul.insert(input[i]);
}
}
}
multiset<int, greater<int>>::iterator it = mul.begin();
for(it = mul.begin(); it != mul.end(); it++)
v.push_back(*it);
return v;
}
};