题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
方法一:不修改原数组,时间复杂度O(NlgK)
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> result;
int length = input.size();
if(length <= 0 || k <= 0 || k > length)
return result;
for(int i = 0; i < input.size(); i++)
{
if(result.size() < k)
result.push_back(input[i]);
else
{
for(int j = k / 2; j >= 0; j--)
HeadAdjust(result, j, k);
for(int j = k - 1; j > 0; j--)//heapsrot
{
swap(result[0], result[j]);
HeadAdjust(result, 0, j);
}
if(result[k-1] > input[i])
result[k-1] = input[i];
}
}
return result;
}
private:
void HeadAdjust(vector<int> &input, int parent, int length){
int temp = input[parent];
int child = 2 * parent + 1;
while(child < length){
if(child + 1 < length && input[child] < input[child+1]){
child++;
}
if(temp >= input[child]){
break;
}
input[parent] = input[child];
parent = child;
child = 2 * parent + 1;
}
input[parent] = temp;
}
};
方法二:变动原数组,时间复杂度O(NlgK)
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 len = input.size();
for(int i = k/2 - 1; i >= 0; --i)
{
sift(input,i,k-1);//建立初始大根堆;
}
for(int j = k; j < len; ++j)//从第k个元素开始与小根堆的根节点比较
{ //0~k-1的元素已成堆
if(input[j] < input[0])
{
int temp = input[0];
input[0] = input[j];
input[j] = temp;
sift(input,0,k-1);//调整堆
}
}
for(int i = 0; i < k; ++i)
res.push_back(input[i]);
return res;
}
void sift(vector<int> &input, int low, int high)//需要修改input,用引用
{
int i = low;
int j = 2*i + 1;//注意下标更新,从0开始需加1
int tmp = input[low];
while(j <= high)
{
if(j+1 < high && input[j] < input[j+1])
j++;
if(tmp < input[j])
{
input[i] = input[j];
i = j;//修改i,j的值,以便继续向下筛选
j = 2*i + 1;//
}
else
break;
}
input[i] = tmp;//被筛选的节点放入最终位置
}
};