剑指Offer:最小的k个数(JAVA实现)

这篇博客探讨了如何解决TopK问题,即找出数组中最大的k个数。作者提供了两种解决方案:一是利用最大堆,保持堆的大小为k,时间复杂度为O(nlogk),空间复杂度为O(k);二是采用快速排序的思想,通过分区操作找到k个最小的元素,时间复杂度为O(n),最坏情况为O(n^2),但会改变原数组。这两种方法都涉及到了排序算法和数据结构的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题:点击此处

考点:
TopK:即前最大k个数或前最小k个数
最大堆,最小堆
快排
这道题非常考验综合能力

思路一:

使用内置排序工具,进行排序,这个做法不明智。
时间复杂度O(nlogn)
空间复杂度O(1)

思路二:(比较好实现)

使用最大堆,来维持一个k大小的的堆。(手动实现一个堆也是不现实的,也要用内置工具函数,即PriorityQueue)
时间复杂度O(nlogk)
空间复杂度O(k)
优点:不用改变数组

思路三:(比较高效)

利用快排的思想,将数组patition为k前和k后
时间复杂度是O(n),最坏的情况是O(n2)
空间复杂度是O(n2)
缺点:会改变数组

思路二

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(k == 0){
            return new int[0];
        }
        int[] ans = new int[k];
        PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>(){
            public int compare(Integer num1,Integer num2){
                return num2 - num1;
            }
        });
        for(int i = 0; i < k;i++){
            queue.offer(arr[i]);
        }
        for(int i = k; i<arr.length; i++){
            if(queue.peek() > arr[i]){
                queue.poll();
                queue.offer(arr[i]);
            }
        }
        for(int i = 0;i<k;i++){
            ans[i] = queue.poll();
        }
        return ans;
    }
}

思路三

class Solution {
    
    public int[] getLeastNumbers(int[] arr, int k) {
        if(k == 0){
            return new int[0];
        }
        quickSortForTopK(arr,0,arr.length-1,k);
        int[] ans = new int[k];
        for(int i = 0; i< k;i++){
            ans[i] = arr[i];
        }
        return ans;
    }

    public void quickSortForTopK(int[] arr,int left,int right,int k){
        if(left >= right){
            return;
        }
        int index = patition(arr,left,right);
        int num = index-left+1;
        if(num == k){
            return;
        }
        if(num > k){
            quickSortForTopK(arr,left,index-1,k);
        }else{
            quickSortForTopK(arr,index+1,right,k-num);
        }
    }

    public int patition(int[] arr,int left,int right){
        Random random = new Random();
        int rnum = random.nextInt(right-left+1)+left;
        swap(arr,left,rnum);
        int pivot = arr[left];
        int le = left;
        for(int i = left+1; i<= right; i++){
            if( arr[i] <= pivot ){
                le++;
                swap(arr,i,le);
            }
        } 
        swap(arr,left,le);
        return le;
    }

    public void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值