LeetCode——面试题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

解法一:

调用Arrays.sort()方法排序,Arrays.copyOf()方法截取数组

class Solution {
      public int[] getLeastNumbers(int[] arr, int k) {
       //排序取前k项
        Arrays.sort(arr);
        return Arrays.copyOf(arr, k);
    }
}

在这里插入图片描述

解法二:

快速排序求解。这里我们只需要知道前k项的元素是什么,并不关注该数组是否完成了排序,故每进行一次快排后都将中头尾两指针相遇的下标返回与k-1进行比较。当两值相等时使用Arrays.copyOf()方法截取数组。
自己写快排的时候遇到了几个坑,导致运行的时候要么就是没正确排序,要么就是程序一直卡住不动,这里总结了一下写快速排序需要注意的点:

  • 进入快排方法时对传入下标进行一次判断。
  • 基准值选定为起始或末尾位置的值后,对数组进行遍历时,要先遍历与基准值相对的指针,如选用数组起始位置的值为基准值,则数组遍历要先从尾部开始,否则无法正确排序
  • 从选定基准值那一端遍历时,进行元素大小比较,使用大于等于或小于等于

详细的解释见下方代码,解法参考:LeetCode题解地址

class solution{
	 public int[] getLeastNumbers(int[] arr, int k) {
        if (k == 0 || arr.length == 0) {
            return new int[0];
        }
        // 最后一个参数表示我们要找的是下标为k-1的数
        return quickSearch(arr, 0, arr.length - 1, k - 1);
    }

    private int[] quickSearch(int[] nums, int low, int high, int k) {
        // 每快排切分1次,找到排序后下标为j的元素,如果j恰好等于k就返回j以及j左边所有的数;
        int i = partition(nums, low, high);
        if (i == k) {
            return Arrays.copyOf(nums, i + 1);
        }
        // 否则根据下标j与k的大小关系来决定继续切分左段还是右段。
        else if(i<k){
            return quickSearch(nums, i+1, high, k);
        }else{
            return quickSearch(nums, low, i-1, k);
        }
    }

   // 快排切分,返回下标j,使得比nums[i]小的数都在i的左边,比nums[i]大的数都在i的右边。
    private int partition(int[] nums, int low, int high) {
        //可防止程序卡住不运行
        if(low>=high){
            return high;
        }       
        //基准值,为了方便一般选用头尾位置的值,这里选用的是low的值
        int pivot=nums[low];
        //数组头尾双指针
        int i=low;
        int j=high;
        //i所指处的指比基准值大就停下,j所指处的指比基准值小就停下,然后两个位置的值交换
        while(i<j){

            while(i<j&&nums[j]>pivot){
                j--;
            }
            //由于遍历是第一个就是基准值,所以这里使用<=
            while(i<j&&nums[i]<=pivot){
                i++;
            }
            if(i<j){
                int temp = nums[j];
                nums[j] = nums[i];
                nums[i] = temp;
            }
        }
        //当i,j相遇时交换相遇位置
        //交换完位置之后左边都是小于基准值的元素,右边都是大于基准值的元素
        nums[low]=nums[i];
        nums[i]=pivot;
        //返回这个相遇位置的下标
        return i;
    }

}

在这里插入图片描述

发布了24 篇原创文章 · 获赞 4 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_44804750/article/details/104997965