剑指 Offer 40. 最小的k个数(leetcode每日打卡)

题目描述

输入整数数组 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]

思路

快速排序分组

题目只要求返回最小的 k 个数,对这 k 个数的顺序并没有要求。因此,只需要将数组划分为 最小的 k 个数 和 其他数字 两部分即可,而快速排序的哨兵划分可完成此目标。

根据快速排序原理,如果某次哨兵划分后 基准数正好是第 k+1 小的数字 ,那么此时基准数左边的所有数字便是题目所求的 最小的 k 个数 。

根据此思路,考虑在每次哨兵划分后,判断基准数在数组中的索引是否等于 k ,若 true 则直接返回此时数组的前 kk个数字即可。

若 k < i ,代表第 k+1 小的数字在 左子数组 中,则递归左子数组; 若 k > i ,代表第 k+1 小的数字在 右子数组 中,则递归右子数组; 若 k = i,代表此时 arr[k] 即为第 k+1 小的数字,则直接返回数组前 k 个数字即可;

题解

//输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(k>=arr.length){return arr;}
        return quickSort(arr,0,arr.length-1,k);
    }
    public int[] quickSort(int[]arr, int left,int right,int k){
        int l=left;
        int r=right;
        int temp=arr[left];
        while(l<r){
            while(l<r && arr[r]>=temp){
                r--;
                }
            while(l<r && arr[l]<=temp){
                l++;
                }
            swap(arr,l,r);
        }
        swap(arr,left,l);
        if(k>l){return quickSort(arr,l+1,right,k);}
        if(k<l){return quickSort(arr,left,l-1,k);}
        return Arrays.copyOf(arr,k);

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

空间复杂度划分函数的平均递归深度为O(logN)

时间复杂度 总体时间复杂度为O(N)

添加备注

执行用时:2 ms, 在所有 Java 提交中击败了97.06%的用户

内存消耗:39.7 MB, 在所有 Java 提交中击败了57.95%的用户

通过测试用例:38 / 38

经验分享 程序员 微信小程序 职场和发展