剑指 Offer 40 最小的k个数

题目:给一个无序数组,求前k个最小的数,排好序放到数组里输出。

public int[] getLeastNumbers(int[] arr, int k)

思路:1.先用快速排序,然后直接用Arrays.copyOf(arr,k)截取前k个元素并复制为新的数组返回,原数组不变。

快速排序第一个元素为标准,且标准只在最后交换一次到中间

快速排序是以第一个元素为标准,但是这个标准不移动,而是让其它元素进行交换移动,最后才把标准交换到中间。标准只交换一次。

快速排序自己实现实现

 	/*
    快排,模板题,背模板
     */
    public int[] getLeastNumbers(int[] arr, int k) {
        qsort(arr,0,arr.length-1);
        /*
        Arrays.copyOf(int[] arr,int newLength)
        可以截取arr前newLength个元素,并且复制出来。不改变原数组。
        若newLength大于arr.length则多出来的默认补0
         */
        int[] res = Arrays.copyOf(arr, k);
        return res;
    }

    /*
    快排思路:
    nums[l]作为标准不动,i,j指针移动。
    j从右往左移动找到一个小于标准的值,i从左往右移动找到一个大于标准的值。
    然后i,j的值交换。
    直到i,j重合后,把标准交换到中间
     */
    public void qsort(int[] nums, int l, int r) {
        /*
        l>r可根据递归式子简单推断(是标准左边或右边没有元素的情况)
        l==r是标准左边或右边只有一个元素的情况
         */
        if(l >= r) return;
        //i,j用来移动
        int i = l,j = r;
        /*
        i等于j时重合,此时需要把标准交换过来。
        否则i,j再变化就i大于j,无法让标准交换到中间了
        */
        while(i < j){
            /*
            里面也可能先i等于j,等于就退出
             nums[l]是标准
             */
            while(i < j && nums[j] >= nums[l]) j--;
            while(i < j && nums[i] <= nums[l]) i++;
            //此时i等于j,交换
            swap(nums,i,j);
        }
        //把标准交换到中间,nums[l]为标准
        swap(nums,i,l);
        //递归分为两部分
        qsort(nums,l,i-1);
        qsort(nums,i+1,r);
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

2.基于快排的优化方法

优化思路:当标准交换到下标为k时,该标准大于前面的(下标从0 1 … k-1,一共k个),小于后面的。所以这前k个就是要求的topk的最小值

实际修改只需要在递归时加上i与k的判断即可。(在qsortPro(nums,l,i-1) 和 qsortPro(nums,i+1,r) 加,当i不等于k时就往左或右区间移动就行了),i等于k是什么都不做,正好方法结束。

	/*
    快排,模板题,背模板
     */
    public int[] getLeastNumbers(int[] arr, int k) {
        qsortPro(arr,0,arr.length-1,k);
        int[] res = Arrays.copyOf(arr, k);
        return res;
    }

    public void qsortPro(int[] nums, int l, int r,int k) {
        /*
        l>r可根据递归式子简单推断(是标准左边或右边没有元素的情况)
        l==r是标准左边或右边只有一个元素的情况
         */
        if(l >= r) return;
        //i,j用来移动
        int i = l,j = r;
        //i等于j时重合,此时需要把标准交换过来。否则i,j再变化就i大于j了
        while(i < j){
            /*
            里面也可能先i等于j,等于就退出
             nums[l]是标准
             */
            while(i < j && nums[j] >= nums[l]) j--;
            while(i < j && nums[i] <= nums[l]) i++;
            //此时i等于j,交换
            swap(nums,i,j);
        }
        //把标准交换到中间,nums[l]为标准
        swap(nums,i,l);
        //递归分为两部分
        if(i > k) qsortPro(nums,l,i-1,k);
        if(i < k) qsortPro(nums,i+1,r,k);
        /*
        i等于k时结束,此时标准的下标正好等于k
        0 - k-1 正好为结果
        */
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值