题目:
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8则最小的4个数字为1,2,3,4
解法:
1、本题思想主要是堆排序。当然如果直接对所有数字使用堆排序或者快排,时间复杂度为o(n*logn)
2、本题利用改进的堆排序,时间复杂度为o(n*logk)
3、主要思想为:
(一)提取数组中的前k个数,构建k个数初始大根堆heap,即heap[0]为前k个数中最大的值
(二)利用遍历,从第 i=k+1~n个数,比较新加入的数number[i] 和heap[0],如果number[i] >heap[0]
直接跳过该数,否则用number[i] 替换heap[0],继续调整大根堆。
实质含义为:大根堆heap存储的为从数组中的第0个数开始到当前的第i个数的前k个最小的值。
当i=n-1时即遍历完成时,heap就是整个数组中的最小的K个数,其中heap[0]=数组中最小的k个数中的最大值
但是heap此时仅为大根堆。内部为无序的。 最后仅此一次heap调整排序即可。
此题核心:理解堆排序思想。
要点:注意边界条件的判断。 如以前文章所提。 边界条件判断为 分别判断各函数参数的异常输入 和联合判断参数异常输入。
代码如下:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> k_numbers;
if(input.size()==0 || input.empty()||k<=0||k>input.size())
return k_numbers;
int n = input.size();
//压入前k个数字
for(int i =0;i<k;i++)
k_numbers.push_back(input[i]);
//构建初始大根堆
for(int i=k/2 -1;i>=0;i--)
adjustHeap(k_numbers,i,k-1);
for(int i =k;i<n;i++)
{
if(input[i]<k_numbers[0])
{
k_numbers[0] = input[i];
adjustHeap(k_numbers,0,k-1);
}
}//遍历完毕后,调整大小为k的heap至升序
for(int i=k-1;i>0;i--)
{
swap(k_numbers[i],k_numbers[0]);
adjustHeap(k_numbers,0,i-1);
}
return k_numbers;
}
void adjustHeap(vector<int> &vec,int begin,int end)
{
int parent = begin;
int child = parent*2 +1;
while(child<=end)
{
int value = vec[parent];
if(child < end && vec[child]<vec[child+1])
child++;
if(vec[child]>value) //大根堆
{
swap(vec[child],vec[parent]);
parent =child;
child = parent*2+1;
}
else
break;
}
}