题目:输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
求数组中最小(最大)的n个数通常可以使用大顶堆(小顶堆)的方法来是实现。大顶堆容易获取到堆中最大的数,若当前数比堆顶大,则可以直接舍去,因此更便于维护。小顶堆则相反,适用于求取前n大的数。
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if(k==0)return new int[0];
if(k==arr.length)return arr;
int[] res=new int[k];//复制前k个数,作为大顶堆的数组初始化。
for(int i=0;i<k;i++){
res[i]=arr[i];
}
build(res);//构建大顶堆
//第k个数之后的数依次与堆顶比较;若比堆顶大则直接排除;若比堆顶小则替换当前堆顶,并维护堆。
for(int i=k;i<arr.length;i++){
if(arr[i]<res[0]){
res[0]=arr[i];
maintain(res,0);
}
}
return res;
}
public void build(int[] res){//建大顶堆;将大顶堆用数组的形式表示。
//父节点索引(i-1)/2;左子索引2*i+1;右子索引2*i+2。
int last=(res.length-1)/2;//找出最后一个父节点的位置
while(last>=0){
maintain(res,last--);//对每个父节点进行维护,直到堆顶。
}
}
public void maintain(int[] res,int l){
if(l>=res.length)return;
int c1=2*l+1;//左子节点索引
int c2=2*l+2;//右子节点索引
int max=l;//初始化max为根节点
if(c1<res.length&&res[c1]>res[max])
max=c1;
if(c2<res.length&&res[c2]>res[max])
max=c2;
if(max!=l){//若父节点不是三个节点中最大的,则换位。
int temp=res[l];
res[l]=res[max];
res[max]=temp;
maintain(res,max);//维护新换父节点的子树
}
}
}