题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
方法一
可以利用快排中partition的思想(快排详细分析可以参考快速排序算法)- 随机选中一个数字,在第一次partition之后,得到此时排列中该数字的位置index,位于index左边的值均小于等于该数字,位于index右边的值均大于等于该数字;
- 当index > k-1时,最小的k个数位于index左边,则对index左边的序列进行partition;
- 当index < k - 1时,index左边的数肯定是最小的k个数中的一部分,还有另外一部分位于index右边,所以对index右边的序列进行partition;
- 直到index = k-1,得到最小的k个数。
这种方式的优点是时间复杂度为O(n),缺点就是需要修改输入数组。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> res;
if( input.empty() || k <= 0 || k > input.size() )
return res;
int first = 0;
int last = input.size() - 1;
int index = partition( input, k, first, last );
while( index != (k-1) )
{
if( index > (k-1) )
{
last = index - 1;
index = partition( input, k, first, last );
}
else
{
first = index + 1;
index = partition( input, k, first, last );
}
}
for( int i=0;i<k;i++ )
res.push_back(input[i]);
return res;
}
int partition(vector<int> &input, int k, int first, int last)
{
swap(input[first],input[rand()%(last-first+1)+first]);
int v = input[first];
int i = first+1;
int j = last;
while( 1 )
{
while( i <= last && input[i] < v )
i++;
while( j >= first && input[j] > v )
j--;
if( i >= j )
break;
swap(input[i],input[j]);
i++;
j--;
}
swap(input[j],input[first]);
return j;
}
};
方法二
可以创建一个大小为k的数据容器来存储最小的k个数字,从输入的n个整数中一个一个读入放入该容器中:
- 如果容器中的数字少于k个,则继续向容器中放入新的值;
- 如果容器中已有k个数字,而数组中还有值未加入,此时就不能直接插入了,需要将待插入的值与容器中的最大值进行比较,如果待插入的值大于容器中最大值,则舍弃这个待插入的值,判断下一个;反之,则将容器中最大值删除,将待插入的值放入容器中。直到数组中的所有数都判断完毕,容器中的数就是最小的k个数。
对于这个容器的实现,我们可以使用最大堆的数据结构,最大堆中,根节点的值大于它的子树中的任意节点值。自己实现最大堆比较复杂,C++中,可以使用优先队列来完成这个工作,优先队列中,每次top()、pop()取出的是队列中的最大值。
方法的时间复杂度为O(nlogn)。
优点:
1. 不会改变原来数组;
2. 这种思想,适合处理海量数据,特别是n大k小的情况。在处理海量数据的时候,受内存限制,数据可能不能一次全部读入内存,此时用这种方式也很好处理,只要想每次读入一些数据,与我们的容器中最大值比较,看是否需要进行替换操作。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> res;
if( k <= 0 || k > input.size() )
return res;
priority_queue<int> q;
for( int i=0;i<input.size();i++ )
{
if( i < k )
q.push(input[i]);
else
{
if( input[i] < q.top() )
{
q.pop();
q.push(input[i]);
}
}
}
while( !q.empty() )
{
res.push_back(q.top());
q.pop();
}
return res;
}
};