剑指 Offer 40. 最小的k个数

题目来源

题目描述

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

示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]

示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]

限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000

解题思路
第一种解法

1、使用Partition函数来解决这个问题。
如果基于数组的第k个数字来调整,则使得比第k个数字小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。这样调整之后,位于数组总左边的k个数字就是最小的k个数字(这k个数字不一定是排序的
2、需要注意的一个细节,边界问题,没有考虑到的话会报错
在这里插入图片描述

if(k == 0){
	return new int[0];
}else if(arr.length <= k){
	return arr;
}

3、时间复杂度为O(n),但是需要修改输入的数组,使用Partition会调整数组中数字的顺序。

代码
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(k == 0){
            return new int[0];
        }else if(arr.length <= k){
            return arr;
        }

        quickselect(arr, 0, arr.length - 1, k);
        return Arrays.copyOfRange(arr, 0, k);
    }

    public void quickselect(int[] nums, int start, int end, int k){
        int pivot = nums[end];
        int left = start;

        for(int i = start; i < end; i++){
            if(nums[i] <= pivot)
                swap(nums, left++, i);
        }
        swap(nums, left, end);

        if(left == k)
            return;
        else if(left < k)
            quickselect(nums, left + 1, end, k);
        else
            quickselect(nums, start,  left - 1, k);
    }
    void swap(int[] nums, int i, int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}
第二种解法

大根堆求前k小Java中提供的现成的PriorityQueue默认是小根堆
先创建一个容器来存储k个数字。找出已有k个数中的最大值,然后拿这次待插入的整数和最大值进行比较。如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值,如果待插入的值比当前已有的最大值还要大,则抛弃这个数。

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {

        if(k == 0 || arr.length == 0){
            return new int[0];
        }
        Queue<Integer> pq = new PriorityQueue<>((v1, v2) -> v2 - v1);
        for(int num : arr){
            if(pq.size() < k){
                pq.offer(num);
            }else if(num < pq.peek()){
                pq.poll();
                pq.offer(num);
            }
        }

        int[] res = new int[pq.size()];
        int idx = 0;
        for(int num : pq){
            res[idx++] = num;
        }
        return res;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值