剑指offer40题最小的K个数

第40题://输入整数数组 nums ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
// 示例 1:
//
// 输入:nums = [3,2,1], k = 2
//输出:[1,2] 或者 [2,1]
// 示例 2:
//
// 输入:nums = [0,1,2,1], k = 1
//输出:[0]
// 限制:
//
//
// 0 <= k <= nums.length <= 10000
// 0 <= nums[i] <= 10000
// Related Topics 堆 分治算法
解题思路:
快排变形的方法:(分治)找第K大的数或找前K个大的数都可以用快排选择算法。快速选择算法与快速排序算法的区别在于快速选择算法只需要递归地选择一侧的数组,快速选择算法在本题中我们只需要知道最小的K个数是哪些,并不需要知道它们排序,可以看作是一个不完全的快速排序。我们在进行一次分治后,比如说我们的分割的位置在m,m左边的数都比m小,m右边的数都比m大。所以:
1.若K=m,这样就直接找到了小于k的数。
2.若k<m,则说明k在m以内,在m的左侧数组,我们只需对左侧数组递归就可以。
3.若k>m,则说明中左侧数组中的m个数属于最小的K个数,所以我们还需对右侧数组去寻找最小的k-m个数。对右侧数组进行递归。
具体代码如下:

import java.util.Arrays;

//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public int[] getLeastNumbers(int[] nums, int k) {
        if (k == 0) {
            return new int[0];
        } else if (nums.length <= k) {
            return nums;
        }
        partitionArray(nums, 0, nums.length - 1, k);
        // 数组的前 k 个数此时就是最小的 k 个数,将其存入结果
        int[] res = new int[k];
        for (int i = 0; i < k; i++) {
            res[i] = nums[i];
        }
        return res;
    }

    void partitionArray(int[] nums, int lo, int hi, int k) {
        int m = quickselect(nums, lo, hi);
        if (k == m) {
            // 正好找到最小的 k(m) 个数
            return;
        } else if (k < m) {
            // 最小的 k 个数一定在前 m 个数中,递归划分
            partitionArray(nums, lo, m - 1, k);
        } else {
            // 在右侧数组中寻找最小的 k-m 个数
            partitionArray(nums, m + 1, hi, k);
        }
    }

    int quickselect(int[] nums, int start, int end) {
        /*循环找比标准数大的数和比标准数小的数*/
            /*把数组中的第0个数字作为标准数*/
            int stard = nums[start];
            /*记录需要排序的下标*/
            int low = start;
            int high = end;
            while (low < high) {
                /*右边的数字比标准数大*/
                while (low < high && stard <= nums[high]) {
                    high--;
                }
                /*使用右边的数字替换左边的数*/
                nums[low] = nums[high];
                /*如果左边的数字比标准数小*/
                while (low < high && nums[low] <= stard) {
                    low++;
                }
                nums[high] = nums[low];
            }
            /*把标准数赋给低所在的位置的元素*/
            nums[low] = stard;
        return low;
        }

    }

全部评论

相关推荐

点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
2024-12-18 15:35
程序员牛肉:完全是在胡写简历。 我很好奇你干嘛要在教育经历里面写你是软件二班的班长?你写它的目的是什么?我觉得真的就是很突兀。给我第一感觉就是:你真的是一个心智健全的成年人吗? 另外我也很好奇你是怎么做到参加了这么多所谓的计算机比赛,完事儿一个拿得出手的项目都没有。 自己的项目经历还是图书馆管理系统这种垃圾东西……我的的建议是你都不如大幅度删减一下自己的水奖项,看着真的给人一种又水又学傻了的感觉。 计算机不看奖项,看院校和个人能力。 计算机是强工科,你要投后端的你就应该明白,人家招你进去是指望你干活儿的。那你觉得你这份简历有展示出你的后端水平吗? 你动动你的脑子想一想,人家面试官要想通过你的简历看出你的项目开发能力,最重要的板块就是两个,第一个是你的实习,第二个是你的项目。你没有实习,是不是就应该在项目上好好琢磨琢磨? 你自己看看你项目写的什么描述,你作为一个要后端岗位的应届生,你对你自己项目的描述还仅仅停留在使用mySQL,使用JAVA,使用spring boot框架。给人一眼感觉就感觉完全就是你做的玩具。可能就是你哪一个学期做的课设。 对于应届生来讲,在项目板块要尽量突出自己的技术能力,因为谈业务你肯定也不懂。简单来讲,你的项目要清晰准确的表达:你用哪种技术解决了现有的哪种技术问题,带来了多少的效益提升? 所有关于项目的描述都围绕我说的这种表达方式去写。不要自己自嗨式的写一堆垃圾上去 你既没有实习项目,又没有一个比较好一点的项目,而且院校也比较差,所以找工作会异常的难找。
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务