题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
我的思路:利用Partition划分,如果index大于k-1,则令end = index - 1,在左边继续找;如果index < k-1,则将start至index之间的数放进vector,令start = index + 1,再找 k - index - 1 个数,这样递归调用的就是要求的这个函数了。
更直观的做法是:利用Partition,让最后返回的 index 位于 k - 1 位置上。
时间复杂度O(n)
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int length = input.size();
vector<int> result;
if(length == 0 || k <= 0 || k > length) return result;
if(k == length) return input;
int start = 0;
int end = length - 1;
int index = Partition(input, length, start, end);
while(index != (k - 1))
{
if(index < k - 1)
{
start = index + 1;
index = Partition(input, length, start, end);
}
else
{
end = index - 1;
index = Partition(input, length, start, end);
}
}
for(int i = 0; i < k; i++)
{
result.push_back(input[i]);
}
return result;
}
int Partition(vector<int>& data, int length, int start, int end)
{
//if(start == end)
//return start;
int index = start;
Swap(&data[index], &data[end]);
int small = start - 1;
for(index = start; index < end; index++)
{
if(data[index] < data[end])
{
++small;
if(small != index)
Swap(&data[index], &data[small]);
}
}
++small;
Swap(&data[end], &data[small]);
return small;
}
void Swap(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
};
调错总结:
(1)index 是跟 k - 1 比而不是跟 k 比,因为当 k 等于vector大小时,index怎样都不可能取到 k的,此时应该等于 k - 1。所以最后放进输出vector的是包含index在内及其左边的数的(<= index)。
(2)报错循环有误或者算法复杂度过大:因为缺少了一个特殊输入测试 k <= 0。
(3)Partition部分之前书写有误,枢轴位置 index = length >> 1有误,因为在函数中length一直没变,而枢轴是会随着区间变化而改变的。为了方便可以直接指定区间左端点start。
(4)Partition中的 if 语句不写的话也就是多走一遍下面的for循环。
//if(start == end)
//return start;
时间复杂度O(nlogk)
优点:
(1)不改变输入vector
(2)适合海量输入,length大而k小。
#include<iterator>
typedef multiset<int, greater<int>> intSet;
typedef multiset<int, greater<int>>::iterator setIterator;
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
intSet leastNumbers;
leastNumbers.clear();
if(k < 1 || k > input.size()) return vector<int>(leastNumbers.begin(), leastNumbers.end());
vector<int>::const_iterator iter = input.begin();
for(; iter != input.end(); iter++)
{
if(leastNumbers.size() < k)
leastNumbers.insert(*iter);
else
{
setIterator iterGreatest = leastNumbers.begin();
if(*iter < *iterGreatest)
{
leastNumbers.erase(iterGreatest);
leastNumbers.insert(*iter);
}
}
}
return vector<int>(leastNumbers.begin(), leastNumbers.end());
}
};
注意返回值的正确表示方法。
最大堆O(nlogk)
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int len=input.size();
if(len<=0||k>len || k<1) return vector<int>();
vector<int> res(input.begin(),input.begin()+k);
//建堆
make_heap(res.begin(),res.end());
for(int i=k;i<len;i++)
{
if(input[i]<res[0])
{
//先pop,然后在容器中删除
pop_heap(res.begin(),res.end());
res.pop_back();
//先在容器中加入,再push
res.push_back(input[i]);
push_heap(res.begin(),res.end());
}
}
//使其从小到大输出
sort_heap(res.begin(),res.end());
return res;
}
};