剑指Offer-40-最小的k个数--topk问题java解法整理

在这里插入图片描述
解法来自于:小美算法 剑指Offer 40题 最小的k个数 java版本 层层深入的三种解法来赢得面试

解法一:排序+取前k个数

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
    int[] res=new int[k];
    //排序
    Arrays.sort(arr);

    for(int i=0;i<k;i++){
        res[i]=arr[i];
    }
    return res;
    }
}

解法二:优先队列大顶堆解法

class Solution {
     //利用小顶堆 大根堆的做法
    public int[] getLeastNumbers(int[] arr, int k) {
    //创建一个队列(默认是最大堆(默认每次被踢出的都是最小的),,我们需要把它改成最小堆(每次被提出的都是最大的))
    Queue<Integer> queue=new PriorityQueue<>((o1,o2)->(o2.compareTo(o1)));

    for(int i:arr){
        queue.add(i);
    //保证队列里只装k个数,且不断保留最小的k个
    while(!queue.isEmpty()&& queue.size()>k) queue.poll();

    }
    //创建新的数组,返回结果
    int[] res=new int[k];
     
    for(int i=0;i<k;i++){
        res[i]=queue.poll();
    }
    return res;

 
    }
}

补充:大顶堆的建立过程:
在这里插入图片描述

解法三:快排+二分

class Solution {
     //快排+二分
    public int[] getLeastNumbers(int[] arr, int k) {
   //排除空数组情况
 if(arr==null||arr.length==0) return new int[0];

 //记录数组两端,不断缩小范围
 int lo=0,hi=arr.length-1;


//使用二分法,不断筛选范围
 while(lo<hi){
//partition是通过不断交换,将区域内某一个随机元素为界划分大小
int index=partition(arr,lo,hi);

//二分的结束条件,如果随机数索引到末尾,退出循环
if(index== k-1)break;
//随机数在k的范围之内,就向后移动
else if(index < k-1) lo=index+1;
//随机数在k的范围之外就向前移动
else hi=index-1;

 } 

    
 return Arrays.copyOfRange(arr,0,k);
    }
    /*
    partition函数原理:   保证最后返回的随机数左面小于随机数,右面大于随机数
    使用pivot标记第一个元素,
    遍历区域里的元素,
    如果遇到当前元素比第一个元素小的时候,若index不和i相等则交换++index的元素和当前元素的位置
    */
    public int partition(int[] arr,int lo,int hi){
       //用pivot记录首个元素,他就是我们最后该返回的元素
        int pivot=arr[lo];
        
        //用index记录当前lo下标
        int index=lo;

        //遍历所有区域内的元素
        for(int i=lo;i<=hi;i++){
            //如果当前元素小于首元素,交换位置
            if(arr[i]<pivot) swap(arr,i,++index);
        }
        //将第一个元素和最后结束的数交换
        swap(arr,lo,index);
        return index;
    }
    public void swap(int[] arr,int i,int j){
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    
}

解法三图示理解:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值