堆结构解决剑指OFFER-最小的K个数问题

题目描述:

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

题目解答:

分析:题目需求为找出n个整数中最小的k个数,考虑使用小顶堆,选k个元素组成一个小顶堆,那么遍历剩下的n-k个元素的时候,如果当前遍历元素大于堆顶元素,该元素还需要继续与小顶堆内的其他元素比较,最差的情况是最初的k个元素就是n个整数中最小的k个数,那么该元素与小顶堆内最后一个元素比较完,该元素大于小顶堆内所有的元素,那么这次比较就是徒劳的,这样性能非常差;考虑使用大顶堆,如果当前遍历的元素大于堆顶元素,直接进行下一个遍历,如果当前遍历元素小于堆顶元素,用该元素替换堆顶元素,再进行大顶堆的调整。

public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
    	//如果k>n or k==0,那么就无法找出最小的k个数,根据方法所需的返回类型返回即可
        if (k > input.length || k==0){
            return new ArrayList<>();
        }
        //用数组去模拟k个节点的堆结构
        int[] maxHeap = new int[k];
        //初始化堆中元素
    	//public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):其中src-原数组,srcPos-从原数组的该位置开始,dest-目标数组,destPos-从目标数组的该位置开始,length-要copy的长度
        System.arraycopy(input,0,maxHeap,0,k);
        //从非叶子节点开始,调整堆
        for (int i = k/2-1;i>=0;i--){
            initiate(i,maxHeap,k);
        }
        //遍历len-k个元素
        for (int i = k;i<input.length;i++){
            if (input[i] < maxHeap[0]){
                //当前位置的值小于大顶堆堆顶位置的值
                //将当前值更新大顶堆堆顶,从堆顶元素开始调整堆
                maxHeap[0] = input[i];
                initiate(0,maxHeap,k);
            }
        }
        //将大顶堆的节点元素进行升序操作
        //将堆顶元素和最后一个元素交换,将除最后一个元素外的大顶堆进行堆维护,重复进行
        for (int i = maxHeap.length-1;i>0;i--){
            int temp = maxHeap[i];
            maxHeap[i] = maxHeap[0];
            maxHeap[0] = temp;
            initiate(0,maxHeap,i);
        }
        ArrayList<Integer> ans = new ArrayList<>();
        for (int i = 0;i<maxHeap.length;i++) {
            ans.add(maxHeap[i]);
        }
        return ans;
    }
	//从index位置开始,将maxHeap数组内的元素调整为大顶堆
    private void initiate(int index, int[] maxHeap, int length) {
        int temp = maxHeap[index];
        //k的初始值是从index的左孩子开始的,k=k*2+1:是找左孩子
        for (int k = index * 2 +1;k<length;k=k*2+1){
            //这里体现如果右孩子大于左孩子的话,k++找到右孩子
            if ((k+1) <length && maxHeap[k+1]>maxHeap[k]){
                k++;
            }
            if (maxHeap[k] > temp){
                //如果当前k即(左右孩子中的一个)>根节点,
                maxHeap[index] = maxHeap[k];
                //更新index的值,代表temp数字最终在堆中的位置,temp的值始终不变
                index=k;
            }else {//此时对应根节点大于左右孩子,就没有必要进行调整
                break;
            }
        }
        //找到最终位置,才进行值的更新
        maxHeap[index] = temp;
    }

代码部分需要好好理解大顶堆的调整过程,如何将起始调整的元素找到最终的位置安放!再就是如何将一个大顶堆从小到大输出,如何对大顶堆进行升序调整!
若是top K问题,则考虑使用小顶堆,思路如上分析所述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值