leetcode 剑指offer 最小的k个数 java

该博客探讨了如何在Java中找出整数数组中最小的k个数。首先,提到直接排序的方法效率不高,然后提出使用快速排序的改进策略,通过调整切分过程来减少不必要的排序。此外,还提到了在数据范围有限时计数排序的适用性,以及利用优先队列(大根堆)实现寻找前K小元素的高效方法。
摘要由CSDN通过智能技术生成

题目描述
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

首先想到的是先排序,再输出前k个,但是不管用什么排序,效果都不是很好。
由于只要找到最小的k个数就好,这k个数不需要从小到大排序,所有快排不需要将所有数字都排序。因为我们是要找下标为k的元素,第一次切分的时候需要遍历整个数组 (0 ~ n) 找到了下标是 j 的元素,假如 k 比 j 小的话,那么我们下次切分只要遍历数组 (0~k-1)的元素就行,反之如果 k 比 j 大的话,那下次切分只要遍历数组 (k+1~n) 的元素就行。

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(k == 0 || arr.length == 0){
            return new int[0];
        }
        return sort(arr,0,arr.length-1,k-1);
    }
        public int partition(int[] arr,int startIndex,int endIndex){
            int pivot = arr[startIndex];
            int left = startIndex;
            int right = endIndex;
            while(left != right){
                while(left<right && arr[right]>pivot){
                    right --;
                }
                while(left < right && arr[left] <= pivot){
                    left ++;
                }
                if(left < right){
                    int p = arr[left];
                    arr[left] = arr[right];
                    arr[right] = p;
                }
            }
            arr[startIndex] = arr[left];
            arr[left] = pivot;
            return left;

        }
        public int[] sort(int[] arr,int startIndex,int endIndex,int k ){
            
            int pivotIndex = partition(arr,startIndex,endIndex);
            if(pivotIndex == k){
               return Arrays.copyOf(arr, pivotIndex+1) ;
            
            }
            return pivotIndex > k? sort(arr, startIndex, pivotIndex - 1, k): sort(arr, pivotIndex + 1, endIndex, k);          
        }
    
}

计数排序:
数据范围有限的情况下可以使用计数排序

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(k==0 || arr.length == 0){
            return new int[0];
        }
        int counter[] = new int[10001];
        for(int a:arr){
            counter[a]++;
        }
        int res[] = new int[k];
        int index = 0;
        for(int i = 0;i<counter.length;i++){
            while(counter[i] > 0 && index <k){
                res[index++] = i;
                counter[i] --;
            }
    }
    return res;
}
}

PriorityQueue:
本题是求前 K 小,因此用一个容量为 K 的大根堆,每次 poll 出最大的数,那堆中保留的就是前 K 小。

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
       if(k == 0 || arr.length == 0){
           return new int[0];
       }
        
        Queue<Integer> q = new PriorityQueue<>((v1,v2)->v2-v1);
        for(int num:arr){
            if(q.size()<k){
                q.offer(num);
            }else if(num<q.peek()){
                q.poll();
                q.offer(num);
            }
        }
        int[] res = new int[q.size()];
        int index = 0;
        for(int num:q){
            res[index++] = num;
        }
        return res;
    }    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值